199 lines
6.1 KiB
C#
199 lines
6.1 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Sirenix.OdinInspector;
|
|
using UnityEngine;
|
|
using UnityEngine.Pool;
|
|
|
|
namespace BlueWater
|
|
{
|
|
public class LiquidController : MonoBehaviour
|
|
{
|
|
[SerializeField]
|
|
private Renderer _renderTexture;
|
|
|
|
[SerializeField]
|
|
private Renderer _liquidRenderer;
|
|
|
|
[SerializeField, Required]
|
|
private Liquid _liquidObject;
|
|
|
|
[SerializeField, Required]
|
|
private Transform _spawnTransform;
|
|
|
|
[SerializeField]
|
|
private Transform _spawnLocation;
|
|
|
|
[SerializeField]
|
|
private Collider2D _reachedCollider;
|
|
|
|
[SerializeField]
|
|
private int _objectPoolCount = 1000;
|
|
|
|
[SerializeField]
|
|
private Color _liquidColor = new(0f, 0.7294118f, 1f, 1f);
|
|
|
|
[SerializeField, Tooltip("1초에 차는 %")]
|
|
private float _pouringRate = 20f;
|
|
|
|
[SerializeField]
|
|
private int _liquidsPerSecond = 100;
|
|
|
|
[SerializeField, Range(0f, 100f)]
|
|
private float _currentLiquidAmount;
|
|
|
|
private IObjectPool<Liquid> _objectPool;
|
|
private List<Liquid> _activeLiquids = new();
|
|
private Dictionary<Color, float> _colorTimes = new();
|
|
|
|
private Material _instanceMaterial;
|
|
private bool _isPouring;
|
|
private float _startTime = float.PositiveInfinity;
|
|
private float _timeInterval;
|
|
private float _liquidPerObject;
|
|
|
|
// Hashes
|
|
private static readonly int _liquidAmountHash = Shader.PropertyToID("_LiquidAmount");
|
|
private static readonly int _liquidColorHash = Shader.PropertyToID("_LiquidColor");
|
|
|
|
private void Awake()
|
|
{
|
|
_objectPool = new ObjectPool<Liquid>(CreateObject, OnGetObject, OnReleaseObject, OnDestroyObject, maxSize: _objectPoolCount);
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
_instanceMaterial = Instantiate(_liquidRenderer.material);
|
|
_liquidRenderer.material = _instanceMaterial;
|
|
|
|
_timeInterval = 1f / _liquidsPerSecond;
|
|
_liquidPerObject = _pouringRate / _liquidsPerSecond;
|
|
_instanceMaterial.SetFloat(_liquidAmountHash, 0f);
|
|
}
|
|
|
|
private void Update()
|
|
{
|
|
if (_isPouring)
|
|
{
|
|
if (_currentLiquidAmount >= 100f)
|
|
{
|
|
InActiveIsPouring();
|
|
return;
|
|
}
|
|
|
|
if (Time.time - _startTime >= _timeInterval)
|
|
{
|
|
_objectPool.Get();
|
|
|
|
if (_colorTimes.ContainsKey(_liquidColor))
|
|
{
|
|
_colorTimes[_liquidColor] += _timeInterval;
|
|
}
|
|
else
|
|
{
|
|
_colorTimes[_liquidColor] = _timeInterval;
|
|
}
|
|
|
|
_startTime = Time.time;
|
|
}
|
|
}
|
|
}
|
|
|
|
private Liquid CreateObject()
|
|
{
|
|
var instance = Instantiate(_liquidObject, _spawnTransform.position, Quaternion.identity, _spawnLocation);
|
|
instance.SetManagedPool(_objectPool);
|
|
instance.Initialize(this, _reachedCollider, _liquidColor);
|
|
return instance;
|
|
}
|
|
|
|
private void OnGetObject(Liquid liquid)
|
|
{
|
|
liquid.transform.position = _spawnTransform.position;
|
|
liquid.transform.rotation = Quaternion.identity;
|
|
liquid.Initialize(this, _reachedCollider, _liquidColor);
|
|
if (_renderTexture && _renderTexture.material.GetColor("_Color") != _liquidColor)
|
|
{
|
|
_renderTexture.material.SetColor("_Color", _liquidColor);
|
|
}
|
|
liquid.gameObject.SetActive(true);
|
|
_activeLiquids.Add(liquid);
|
|
}
|
|
|
|
private void OnReleaseObject(Liquid liquid)
|
|
{
|
|
liquid.gameObject.SetActive(false);
|
|
_activeLiquids.Remove(liquid);
|
|
}
|
|
|
|
private void OnDestroyObject(Liquid liquid)
|
|
{
|
|
Destroy(liquid.gameObject);
|
|
_activeLiquids.Remove(liquid);
|
|
}
|
|
|
|
private Color MixColorsByTime()
|
|
{
|
|
var totalTime = _colorTimes.Values.Sum();
|
|
|
|
// 혼합된 색상 초기화 (검은색)
|
|
var mixedColor = Color.black;
|
|
|
|
// 색상 혼합
|
|
foreach (var element in _colorTimes)
|
|
{
|
|
var color = element.Key;
|
|
var time = element.Value;
|
|
var ratio = time / totalTime;
|
|
|
|
mixedColor += color * ratio;
|
|
}
|
|
|
|
mixedColor.a = 1f;
|
|
|
|
return mixedColor;
|
|
}
|
|
|
|
[Button("기본 색상")]
|
|
private void DefaultColor() => _liquidColor = new Color(0f, 0.7294118f, 1f, 1f);
|
|
|
|
public void ReleaseAllObject()
|
|
{
|
|
// 뒤에서부터 Remove해야 오류가 없음
|
|
for (var i = _activeLiquids.Count - 1; i >= 0; i--)
|
|
{
|
|
_activeLiquids[i].Destroy();
|
|
}
|
|
|
|
_colorTimes.Clear();
|
|
_currentLiquidAmount = 0f;
|
|
_instanceMaterial.SetFloat(_liquidAmountHash, 0f);
|
|
}
|
|
|
|
public void ActiveIsPouring()
|
|
{
|
|
_startTime = Time.time;
|
|
_isPouring = true;
|
|
}
|
|
|
|
public void InActiveIsPouring()
|
|
{
|
|
_isPouring = false;
|
|
}
|
|
|
|
public void OnLiquidReached()
|
|
{
|
|
// 컵에 채워진 액체의 양을 증가시킴
|
|
_currentLiquidAmount += _liquidPerObject;
|
|
_currentLiquidAmount = Mathf.Clamp(_currentLiquidAmount, 0f, 100f);
|
|
var liquidAmount = _currentLiquidAmount * 0.01f;
|
|
_instanceMaterial.SetFloat(_liquidAmountHash, liquidAmount);
|
|
_instanceMaterial.SetColor(_liquidColorHash, MixColorsByTime());
|
|
|
|
// 액체가 100%에 도달하면 pouring을 멈춤
|
|
if (_currentLiquidAmount >= 100f)
|
|
{
|
|
InActiveIsPouring();
|
|
}
|
|
}
|
|
}
|
|
} |