Skip to content

Instantly share code, notes, and snippets.

@CKShare
Created March 29, 2018 01:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CKShare/a3c00c01b9072b7c381c994359a78608 to your computer and use it in GitHub Desktop.
Save CKShare/a3c00c01b9072b7c381c994359a78608 to your computer and use it in GitHub Desktop.
오브젝트별 타임스케일 적용
public interface ITimeControl
{
void Initialize();
void AdjustTimeScale(float timeScale);
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(SphereCollider))]
public class TimeArea : MonoBehaviour
{
private struct ScaleTarget
{
public ScaleTarget(Transform transform, TimeController timeController)
{
Transform = transform;
TimeController = timeController;
}
public Transform Transform { get; private set; }
public TimeController TimeController { get; private set; }
}
[SerializeField]
private AnimationCurve _scaleCurve;
[SerializeField]
private float _scaleDelay = 0.1F;
[SerializeField]
private float _duration = 4F;
private Rigidbody _rigidbody;
private SphereCollider _collider;
private List<ScaleTarget> _targets = new List<ScaleTarget>();
private Coroutine _scaleCoroutine;
private WaitForSeconds _scaleDelayRef;
private WaitForSeconds _durationRef;
private void Awake()
{
_collider = GetComponent<SphereCollider>();
_rigidbody = GetComponent<Rigidbody>();
_rigidbody.isKinematic = true;
_collider.isTrigger = true;
_scaleDelayRef = new WaitForSeconds(_scaleDelay);
_durationRef = new WaitForSeconds(_duration);
}
private void OnEnable()
{
StartCoroutine(Deactivate());
_scaleCoroutine = StartCoroutine(Scale());
}
private void OnDisable()
{
foreach (var target in _targets)
target.TimeController.RemoveEffector(this);
_targets.Clear();
StopCoroutine(_scaleCoroutine);
}
private void OnTriggerEnter(Collider collider)
{
var timeController = collider.GetComponent<TimeController>();
if (timeController != null)
{
_targets.Add(new ScaleTarget(collider.transform, timeController));
}
}
private void OnTriggerExit(Collider collider)
{
var timeController = collider.GetComponent<TimeController>();
if (timeController != null)
{
int index = _targets.FindIndex(x => x.Transform == collider.transform);
_targets.RemoveAt(index);
timeController.RemoveEffector(this);
}
}
private IEnumerator Deactivate()
{
yield return _durationRef;
gameObject.SetActive(false);
}
private IEnumerator Scale()
{
Bounds bounds = _collider.bounds;
Vector3 center = bounds.center;
float radius = bounds.extents.x;
while (true)
{
foreach (var target in _targets)
{
float distance = (target.Transform.position - center).magnitude;
float ratio = Mathf.Clamp(distance, 0F, radius) / radius;
float timeScale = _scaleCurve.Evaluate(ratio);
target.TimeController.AddOrSetEffector(this, timeScale);
}
yield return _scaleDelayRef;
}
}
}
using UnityEngine;
public class TimeControllableAnimator : ITimeControl
{
[SerializeField]
private Animator _animator;
private float _speed;
public void Initialize()
{
_speed = _animator.speed;
}
public void AdjustTimeScale(float timeScale)
{
_animator.speed = _speed * timeScale;
}
}
using UnityEngine;
public class TimeControllableAudioSource : ITimeControl
{
[SerializeField]
private AudioSource _audioSource;
private float _pitch;
public void Initialize()
{
_pitch = _audioSource.pitch;
}
public void AdjustTimeScale(float timeScale)
{
_audioSource.pitch = _pitch * timeScale;
}
}
using UnityEngine;
public class TimeControllableParticleSystem : ITimeControl
{
[SerializeField]
private ParticleSystem _particleSystem;
private float _simulationSpeed;
public void Initialize()
{
_simulationSpeed = _particleSystem.main.simulationSpeed;
}
public void AdjustTimeScale(float timeScale)
{
var module = _particleSystem.main;
module.simulationSpeed = _simulationSpeed * timeScale;
}
}
using System.Collections.Generic;
using UnityEngine;
using Sirenix.OdinInspector;
[DefaultExecutionOrder(-32000)]
public class TimeController : SerializedMonoBehaviour
{
[ShowInInspector, ReadOnly]
private float _timeScale = 1F;
[SerializeField, HideReferenceObjectPicker]
private ITimeControl[] _components = new ITimeControl[0];
private Dictionary<object, float> _effectors = new Dictionary<object, float>();
private bool _isChanged = false;
private void Awake()
{
foreach (var comp in _components)
comp.Initialize();
}
private void FixedUpdate()
{
DeltaTime = Time.fixedDeltaTime * TimeScale;
}
private void Update()
{
DeltaTime = Time.deltaTime * TimeScale;
}
public void AddOrSetEffector(object key, float value)
{
_effectors[key] = value;
_isChanged = true;
}
public void RemoveEffector(object key)
{
_effectors.Remove(key);
_isChanged = true;
}
private void Calculate()
{
float timeScale = 1F;
foreach (var effector in _effectors)
timeScale *= effector.Value;
TimeScale = timeScale;
}
public float TimeScale
{
get
{
if (_isChanged)
{
Calculate();
_isChanged = false;
}
return _timeScale;
}
private set
{
_timeScale = value;
foreach (var comp in _components)
comp.AdjustTimeScale(_timeScale);
}
}
public float DeltaTime { get; private set; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment