126 lines
4.0 KiB
C#
126 lines
4.0 KiB
C#
using Unity.Mathematics;
|
|
using UnityEngine;
|
|
using UnityEngine.Pool;
|
|
using Object = UnityEngine.Object;
|
|
|
|
namespace DanieleMarotta.RiversongCodeShowcase
|
|
{
|
|
public class BuildToolPreview
|
|
{
|
|
private readonly GameConfig.UIConfig.BuildToolConfig _config;
|
|
|
|
private readonly ITileSpace _tileSpace;
|
|
|
|
private BuildingDefinition _building;
|
|
|
|
private Vector3 _tilt;
|
|
|
|
private Vector3 _tiltVelocity;
|
|
|
|
private float _yaw;
|
|
|
|
private float _yawVelocity;
|
|
|
|
public BuildToolPreview(GameConfig.UIConfig.BuildToolConfig config, ITileSpace tileSpace)
|
|
{
|
|
_config = config;
|
|
_tileSpace = tileSpace;
|
|
}
|
|
|
|
public GameObject PreviewObject { get; private set; }
|
|
|
|
public bool IsVisible => PreviewObject && PreviewObject.activeSelf;
|
|
|
|
public float3 Position => PreviewObject ? PreviewObject.transform.position : Vector3.zero;
|
|
|
|
public void PrepareForBuilding(BuildingDefinition building)
|
|
{
|
|
_building = building;
|
|
}
|
|
|
|
public void Release()
|
|
{
|
|
ClearPreviewObject();
|
|
}
|
|
|
|
public void Update(bool isValid, Vector3 pointer, Directions orientation)
|
|
{
|
|
if (!PreviewObject)
|
|
{
|
|
if (_building.Visualization.IsDone)
|
|
CreatePreviewObject();
|
|
else
|
|
return;
|
|
}
|
|
|
|
var snap = !PreviewObject.activeSelf && isValid;
|
|
if (snap)
|
|
{
|
|
_tilt = Vector3.zero;
|
|
_tiltVelocity = Vector3.zero;
|
|
}
|
|
|
|
PreviewObject.SetActive(isValid);
|
|
if (!isValid) return;
|
|
|
|
var rect = TileMath.GetBuildingRect(_tileSpace.WorldToTile(pointer), orientation, _building.Width, _building.Height);
|
|
var position = _tileSpace.GetRectWorldCenter(rect);
|
|
position.y += _config.Height;
|
|
|
|
var dt = Time.unscaledDeltaTime;
|
|
|
|
position = snap ? position : Vector3.Lerp(PreviewObject.transform.position, position, _config.LerpFactor * dt);
|
|
|
|
var yaw = orientation.ToQuaternion().eulerAngles.y;
|
|
_yaw = snap ? yaw : Mathf.SmoothDampAngle(_yaw, yaw, ref _yawVelocity, 0.1f, Mathf.Infinity, dt);
|
|
var rotation = Quaternion.Euler(0, _yaw, 0);
|
|
if (!snap) rotation = SimulateSpring(position, dt) * rotation;
|
|
|
|
PreviewObject.transform.SetPositionAndRotation(position, rotation);
|
|
}
|
|
|
|
private Quaternion SimulateSpring(Vector3 targetPosition, float dt)
|
|
{
|
|
var positionDelta = targetPosition - PreviewObject.transform.position;
|
|
|
|
_tilt -= positionDelta * _config.ImpulseScale;
|
|
_tilt = _tilt.normalized * Mathf.Min(_tilt.magnitude, _config.MaxTilt);
|
|
|
|
_tiltVelocity -= _tilt * (_config.Elasticity * dt);
|
|
_tiltVelocity *= Mathf.Pow(1 - _config.Damping, dt);
|
|
|
|
_tilt += _tiltVelocity * dt;
|
|
|
|
if (_tilt.sqrMagnitude > 0.001f)
|
|
{
|
|
var axis = Vector3.Cross(Vector3.down, _tilt.normalized);
|
|
var angle = _tilt.magnitude / _config.MaxTilt * _config.MaxTiltAngle;
|
|
return Quaternion.AngleAxis(angle, axis);
|
|
}
|
|
|
|
return Quaternion.identity;
|
|
}
|
|
|
|
private void CreatePreviewObject()
|
|
{
|
|
PreviewObject = Object.Instantiate((GameObject)_building.Visualization.Asset);
|
|
PreviewObject.SetLayerRecursively<Renderer>(GameObjectLayers.IgnoreAoE);
|
|
|
|
using var _ = ListPool<HideOnBuildingPreview>.Get(out var hide);
|
|
PreviewObject.GetComponentsInChildren(hide);
|
|
foreach (var obj in hide) obj.gameObject.SetActive(false);
|
|
|
|
// Start the preview in the disabled state, causes the position to be snapped when enabled
|
|
PreviewObject.SetActive(false);
|
|
}
|
|
|
|
public void ClearPreviewObject()
|
|
{
|
|
if (PreviewObject)
|
|
{
|
|
Object.Destroy(PreviewObject);
|
|
PreviewObject = null;
|
|
}
|
|
}
|
|
}
|
|
} |