public class CookingMillMiniGame : MonoBehaviour,ICookingMiniGameHandler
{
float timer = 15; // 15초
float elapsedTimer; // 누적 시간
// 기준
public float direction; // 시계 or 반시계
public bool isClockWise; // 시계방향인지 아닌지
public float angle;
public float speed;
bool isGameOver = false;
Vector2 curPos; // 현재 마우스 위치
Vector2 previousPos;
Vector2 targetPos;
Vector2 centerPos;
[SerializeField]private Transform centerTransform;
private float curAngle;
private float previousAngle;
// 큐 (최단각도, 시간) 구조
public Queue<(float deltaAngle, float time)> angleQueue = new();
float CurAngleFromCenter(Vector2 pos, Vector2 center)
{
Vector2 dir = pos - center; // 센터->pos 방향
return Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
}
#region 리팩토링 이후 사용
public void StartGame()
{
}
public void StopGame()
{
}
public void UpdateGame()
{
}
#endregion
// 테스트용 생명주기함수
void Start()
{
}
void Update()
{
if (isGameOver) return;
timer -= Time.deltaTime;
curPos = Input.mousePosition; // 현 마우스의 위치
Vector2 centerPos = Camera.main.WorldToScreenPoint(centerTransform.position); // 맷돌 정가운데 (중심점)
// 현재 마우스와 중심 사이의 각도를 구한다
CurAngleFromCenter(curPos, centerPos);
// 1. 프레임마다의 각도의 차이를 구한다
float deltaAngle = Mathf.DeltaAngle(curAngle, previousAngle);
// 2. 마우스 회전방향
// (현재 프레임 - 이전 프레임)의 최단각도가 플러스면 시계, 마이너스면 반시계 방향
if(deltaAngle > 0) { isClockWise = true; }
// 3. (현재 프레임 - 이전 프레임)의 각도를 계속해서 큐에 넣어준다
angleQueue.Enqueue((deltaAngle, Time.time));
// * 0.75초마다 계산하기 위해, 큐에 있는 가장 오래된 데이터의 시간값이 0.75초를 넘으면 제거한다
if (angleQueue.Peek().time > 0.75f)
{
angleQueue.Dequeue();
}
// 4. 누적된 회전 각도는 큐에 존재하는 데이터들의 절댓값의 합
float totalAngle = angleQueue.Sum(x => Mathf.Abs(x.deltaAngle));
// 5. 그것을 0.75초로 나누어주면 마우스의 평균 속도
float mouseSpeed = totalAngle / 0.75f;
Debug.Log($"{mouseSpeed}");
// 6. mouseSpeed (180f~250f) 사이를 유지한 시간도 구해야 판정 기준에 쓸 수 있음
if (mouseSpeed >= 180f && mouseSpeed <= 250f)
{
elapsedTimer += Time.deltaTime;
}
// 7.. 모든 처리 이후 초기화
previousAngle = curAngle;
Debug.Log($"deltaAngle: {deltaAngle}, mouseSpeed: {mouseSpeed}, curAngle: {curAngle}, prevAngle: {previousAngle}");
if (timer <= 0f)
{
isGameOver = true;
// 8. 마우스속도와 유지시간을 판정 함수로 넘김
Judge(mouseSpeed, elapsedTimer);
Time.timeScale = 0f;
}
}
/// <summary>
/// 게임종료 후 등급 판정
/// (mouseSpeed를 180f~250f 사이로 유지한 시간을 기준으로 함)
/// </summary>
/// <param name="speed"></param>
/// <param name="time"></param>
void Judge(float speed, float time)
{
// 12초이상 : 상 (perfect)
if (time >= 12f)
{
Debug.Log("Perfect");
}
if (time >= 8f && time <= 11f)
{
Debug.Log("Good");
}
if (time >= 5f && time <= 7f)
{
Debug.Log("Bad");
}
else
{
Debug.Log("Fail");
}
// 8~11초 : 중 (Good)
// 5~7초 : 하 (Bad)
// 5초 미만 || 반대방향 지속 입력 : 실패 (Miss)
}
15초간 진행되는 이 미니게임은 마우스를 원형범위내에서 특정한 회전방향(시계or반시계 랜덤)으로 회전하면서, 목표 속도를 유지 하는 게임이다.
따라서
Mathf.Atan2을 통해 탄젠트 값으로 y/x값을 가지는 radian을 반환한다.
Mathf.Rad2Deg는 radian to degree로, 우리가 일반적으로 사용하는 각도로 변환해주는 과정이다
마우스 커서의 이동에 따라 오브젝트를 움직
https://gnaseel.tistory.com/17
ex)
Quarternion.AngleAxis(30, Vector3.up);
Sets the transform's current rotation to a new rotation that rotates 30 degrees around the y-axis(Vector3.up)
트러블슈팅
Vector2 centerPos = Camera.main.WorldToScreenPoint(centerTransform.position);
->
Vector2 centerPos = RectTransformUtility.WorldToScreenPoint(null, centerTransform.position);
ui는 rectTransform을 가지기 때문에..