Skip to content

Instantly share code, notes, and snippets.

@gamemachine
Last active December 30, 2017 03:23
Show Gist options
  • Select an option

  • Save gamemachine/573baf607f68036f71692bf8d38d7d29 to your computer and use it in GitHub Desktop.

Select an option

Save gamemachine/573baf607f68036f71692bf8d38d7d29 to your computer and use it in GitHub Desktop.
using System.Collections;
using System.Collections.Generic;
using UltimateWater;
using UnityEngine;
namespace AiGame
{
public class KinematicBuoyancy : MonoBehaviour
{
public float DefaultHeight;
public float Width = 6f;
public float Length = 14f;
public Vector3 Gravity = new Vector3(0, -9.81f, 0);
public float AccelerationMulti = 1f;
public float MaxAccel = 0.01f;
public float AccelerationSmooth = 1f;
public float DecelerationConstant = 0.5f;
public float RotationSpeed = 5f;
public float RotationAngleMulti = 6f;
[SerializeField]
private float Height;
private Water Water;
// For debugging
[SerializeField]
private Vector3 front;
[SerializeField]
private Vector3 back;
[SerializeField]
private Vector3 left;
[SerializeField]
private Vector3 right;
private Accelerator Accelerator;
void Awake()
{
Accelerator = new Accelerator(0f, 50f, DecelerationConstant);
if (Water == null)
{
Water = FindObjectOfType<Water>();
}
}
public float GetHeight(Vector3 position)
{
return CalculateVerticalVelocity(position.y, GetWaterLevel(position.x, position.z));
}
public Vector3 GetRotation(Vector3 position)
{
float halfLength = Length / 2f;
float halfWidth = Width / 2f;
front = new Vector3(position.x, position.y, position.z + halfLength);
front.y = GetWaterLevel(front.x, front.z);
back = new Vector3(position.x, position.y, position.z - halfLength);
back.y = GetWaterLevel(back.x, back.z);
left = new Vector3(position.x - halfWidth, position.y, position.z);
left.y = GetWaterLevel(left.x, left.z);
right = new Vector3(position.x + halfWidth, position.y, position.z);
right.y = GetWaterLevel(right.x, right.z);
float zangle = 0f;
float xangle = 0f;
if (front.y > back.y)
{
zangle = -(front.y - back.y);
}
else if (back.y > front.y)
{
zangle = (back.y - front.y);
}
else
{
zangle = 0f;
}
if (left.y > right.y)
{
xangle = -(left.y - right.y);
}
else if (right.y > left.y)
{
xangle = (right.y - left.y);
}
else
{
xangle = 0f;
}
Vector3 targetRot = new Vector3(xangle * RotationAngleMulti, 0f, zangle * RotationAngleMulti);
Quaternion rot = Quaternion.Slerp(transform.rotation, Quaternion.Euler(targetRot), RotationSpeed * Time.deltaTime);
return new Vector3(rot.eulerAngles.x, 0f, rot.eulerAngles.z);
}
public float GetWaterLevel(float x, float z)
{
if (Water == null)
{
return DefaultHeight;
} else
{
//return Water.transform.position.y + Water.GetUncompensatedHeightAt(x, z, Time.time);
return Water.transform.position.y + Water.GetHeightAt(x, z, Time.time);
}
}
private float CalculateVerticalVelocity(float current, float waterLevel)
{
float height = current;
Accelerator.Max = MaxAccel;
height += Gravity.y * Time.deltaTime;
if (height < waterLevel)
{
float force = (waterLevel - height) * Mathf.Exp(AccelerationMulti * Time.deltaTime);
Accelerator.Accelerate(force);
}
Accelerator.Decelerate(DecelerationConstant);
height += Accelerator.Current;
height = Mathf.Lerp(height, waterLevel, AccelerationSmooth * Time.deltaTime);
height = Mathf.Clamp(height, -20f, 20f);
return height;
}
}
}
public class Accelerator
{
public float Min { get; set; }
public float Max { get; set; }
public float Current { get; set; }
public float Deceleration { get; set; }
public Accelerator(float min, float max, float decel)
{
Min = min;
Max = max;
Deceleration = decel;
}
public void Accelerate(float accel)
{
Current = Current + (accel * Time.deltaTime);
Clamp();
}
public void Decelerate(float decel)
{
Current = Current - (decel * Time.deltaTime);
Clamp();
}
private void Clamp()
{
Current = Mathf.Clamp(Current, Min, Max);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment