오류수정
This commit is contained in:
@@ -46,7 +46,7 @@ public class ClickThroughHitTest : MonoBehaviour
|
||||
bool useNoActivate = true;
|
||||
|
||||
[Header("검증용")]
|
||||
[SerializeField] bool showDebugHud = true;
|
||||
[SerializeField] bool showDebugHud = false;
|
||||
|
||||
[Tooltip("커서가 캐릭터 위에 있을 때 미세하게 커지는 반응. 과하면 화면 제한 계산에도 영향을 준다")]
|
||||
[SerializeField] bool visualizeHover = true;
|
||||
|
||||
86
Assets/02_Scripts/Desktop/FrameRateLimiter.cs
Normal file
86
Assets/02_Scripts/Desktop/FrameRateLimiter.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// 프레임레이트를 제한한다. 상시 구동 앱에서는 이게 없으면 안 된다.
|
||||
///
|
||||
/// 기본 상태의 Unity 는 vSync 가 꺼져 있고 targetFrameRate 가 -1 이라
|
||||
/// "낼 수 있는 만큼" 렌더링한다. 거의 빈 씬이면 수백~수천 FPS 가 나오고,
|
||||
/// 그동안 CPU 코어 하나와 GPU 를 계속 물고 있는다. 게임이라면 상관없지만
|
||||
/// 이 앱은 사용자가 다른 일을 하는 내내 떠 있으므로 그대로 두면 안 된다.
|
||||
/// runInBackground = true 라 창이 뒤로 가도 멈추지 않는다는 점이 더 나쁘다.
|
||||
///
|
||||
/// 한 걸음 더: 아무 일도 없을 때는 더 낮춘다. 캐릭터가 발판에 가만히 서 있고
|
||||
/// 커서도 근처에 없다면 초당 몇 장만 그려도 눈에 띄지 않는다. 사용자가 손을
|
||||
/// 가져가거나 캐릭터가 움직이기 시작하면 즉시 올린다.
|
||||
/// </summary>
|
||||
public class FrameRateLimiter : MonoBehaviour
|
||||
{
|
||||
[Header("프레임 제한")]
|
||||
[Tooltip("사용자와 상호작용 중이거나 캐릭터가 움직일 때의 상한")]
|
||||
[Range(15, 144)]
|
||||
[SerializeField] int activeFrameRate = 60;
|
||||
|
||||
[Tooltip("아무 일도 없을 때의 상한. 낮출수록 배터리와 발열에 유리하다")]
|
||||
[Range(5, 60)]
|
||||
[SerializeField] int idleFrameRate = 15;
|
||||
|
||||
[Tooltip("상호작용이 끝난 뒤 이만큼은 높은 프레임을 유지한다(초). " +
|
||||
"값이 0 이면 커서를 뗄 때마다 뚝뚝 끊겨 보인다")]
|
||||
[SerializeField] float activeLinger = 1.5f;
|
||||
|
||||
[Tooltip("끄면 항상 activeFrameRate 로 고정한다")]
|
||||
[SerializeField] bool dropWhenIdle = true;
|
||||
|
||||
[Header("참조 (비우면 씬에서 탐색)")]
|
||||
[SerializeField] ClickThroughHitTest hitTest;
|
||||
[SerializeField] CharacterDragger dragger;
|
||||
[SerializeField] WindowClimber climber;
|
||||
[SerializeField] ChatController chat;
|
||||
|
||||
float activeUntil;
|
||||
int applied = -1;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
if (hitTest == null) hitTest = FindFirstObjectByType<ClickThroughHitTest>();
|
||||
if (dragger == null) dragger = FindFirstObjectByType<CharacterDragger>();
|
||||
if (climber == null) climber = FindFirstObjectByType<WindowClimber>();
|
||||
if (chat == null) chat = FindFirstObjectByType<ChatController>();
|
||||
|
||||
// targetFrameRate 는 vSync 가 꺼져 있어야 듣는다. 품질 레벨이 바뀌면
|
||||
// vSync 가 되살아날 수 있으므로 여기서 못박는다.
|
||||
QualitySettings.vSyncCount = 0;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (IsBusy()) activeUntil = Time.unscaledTime + Mathf.Max(0f, activeLinger);
|
||||
|
||||
bool active = !dropWhenIdle || Time.unscaledTime < activeUntil;
|
||||
Apply(active ? activeFrameRate : idleFrameRate);
|
||||
}
|
||||
|
||||
/// <summary>지금 부드러워야 하는 상황인지.</summary>
|
||||
bool IsBusy()
|
||||
{
|
||||
// 커서가 캐릭터나 채팅창 위에 있다 — 곧 뭔가 할 참이다.
|
||||
if (hitTest != null && (hitTest.IsOverCharacter || hitTest.IsOverUi)) return true;
|
||||
|
||||
if (dragger != null && dragger.IsDragging) return true;
|
||||
|
||||
// 채팅창이 열려 있으면 글자가 흘러나오는 중일 수 있다.
|
||||
if (chat != null && chat.IsOpen) return true;
|
||||
|
||||
// 캐릭터가 제자리에 서 있지 않다면 움직이는 중이다.
|
||||
if (climber != null && climber.State != ClimbState.Standing) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Apply(int frameRate)
|
||||
{
|
||||
if (applied == frameRate) return;
|
||||
applied = frameRate;
|
||||
Application.targetFrameRate = frameRate;
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/Desktop/FrameRateLimiter.cs.meta
Normal file
2
Assets/02_Scripts/Desktop/FrameRateLimiter.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dae22a3bc9e51854088f14115dc44aec
|
||||
@@ -10,13 +10,13 @@
|
||||
[RequireComponent(typeof(DesktopPlatformScanner))]
|
||||
public class PlatformDebugOverlay : MonoBehaviour
|
||||
{
|
||||
[SerializeField] bool show = true;
|
||||
[SerializeField] bool show = false;
|
||||
[SerializeField] float lineThickness = 3f;
|
||||
[SerializeField] Color windowColor = new Color(0.2f, 0.9f, 1f, 0.85f);
|
||||
[SerializeField] Color floorColor = new Color(1f, 0.8f, 0.2f, 0.85f);
|
||||
|
||||
[Tooltip("각 발판에 창 제목을 함께 표시")]
|
||||
[SerializeField] bool showTitles = true;
|
||||
[SerializeField] bool showTitles = false;
|
||||
|
||||
DesktopPlatformScanner scanner;
|
||||
Texture2D pixel;
|
||||
|
||||
@@ -38,6 +38,7 @@ void Awake()
|
||||
|
||||
const int ID_TOGGLE = 1;
|
||||
const int ID_EXIT = 2;
|
||||
const int ID_AUTOCLIMB = 3;
|
||||
|
||||
delegate IntPtr WndProcDelegate(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
@@ -191,6 +192,15 @@ void ShowContextMenu()
|
||||
if (menu == IntPtr.Zero) return;
|
||||
|
||||
AppendMenuW(menu, MF_STRING, ID_TOGGLE, characterVisible ? "캐릭터 숨기기" : "캐릭터 보이기");
|
||||
|
||||
// 자동 올라타기는 켜고 끄는 항목이라 체크 표시로 현재 상태를 보여준다.
|
||||
var climber = FindFirstObjectByType<WindowClimber>();
|
||||
if (climber != null)
|
||||
{
|
||||
uint flags = MF_STRING | (climber.AutoClimb ? MF_CHECKED : 0);
|
||||
AppendMenuW(menu, flags, ID_AUTOCLIMB, "자동으로 창에 올라가기");
|
||||
}
|
||||
|
||||
AppendMenuW(menu, MF_SEPARATOR, 0, null);
|
||||
AppendMenuW(menu, MF_STRING, ID_EXIT, "종료");
|
||||
|
||||
@@ -216,6 +226,15 @@ void ShowContextMenu()
|
||||
{
|
||||
ToggleCharacter();
|
||||
}
|
||||
else if (cmd == ID_AUTOCLIMB)
|
||||
{
|
||||
var target = FindFirstObjectByType<WindowClimber>();
|
||||
if (target != null)
|
||||
{
|
||||
target.AutoClimb = !target.AutoClimb;
|
||||
Debug.Log($"[TrayIcon] 자동으로 창에 올라가기 = {target.AutoClimb}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ToggleCharacter()
|
||||
@@ -288,6 +307,7 @@ void Cleanup()
|
||||
|
||||
const uint MF_STRING = 0x0000;
|
||||
const uint MF_SEPARATOR = 0x0800;
|
||||
const uint MF_CHECKED = 0x0008; // 항목 앞에 체크 표시
|
||||
|
||||
const uint TPM_RIGHTBUTTON = 0x0002;
|
||||
const uint TPM_RETURNCMD = 0x0100;
|
||||
|
||||
@@ -47,6 +47,7 @@ internal static class Win32
|
||||
public const int SW_SHOW = 5;
|
||||
|
||||
public const int VK_LBUTTON = 0x01;
|
||||
public const int VK_RBUTTON = 0x02;
|
||||
public const int VK_ESCAPE = 0x1B;
|
||||
public const int VK_SHIFT = 0x10;
|
||||
public const int VK_CONTROL = 0x11;
|
||||
|
||||
Reference in New Issue
Block a user