using UnityEngine;
using System.IO;
using System.Collections.Generic;
using OperatorSettings;
///
/// 操作員選單截圖工具 v4
///
/// 自動讀取 PageController.currentPage.pageTitle 作為檔名
/// 支援簡體/繁體/英文三語自動命名
///
/// 按鍵:
/// - F12:截圖(可重複按,同名自動加 _2, _3...)
/// - F9:清除同名計數(切到新頁面後按一下重置計數)
/// - Inspector 即時調整裁切框
///
public class OperatorScreenshotCapture : MonoBehaviour
{
[Header("=== 儲存設定 ===")]
[SerializeField] private string basePath = "C:/Users/tomliu/Desktop/A9+相關/A9+操作員手冊相關/TW手冊/A9+手冊截圖_繁體";
[Header("=== 裁切設定(Inspector 即時調整)===")]
[SerializeField] private bool enableCrop = true;
[SerializeField] private int cropX = 225;
[SerializeField] private int cropY = 76;
[SerializeField] private int cropWidth = 715;
[SerializeField] private int cropHeight = 669;
[SerializeField] private int baseWidth = 952;
[SerializeField] private int baseHeight = 763;
[Header("=== 預覽設定 ===")]
[SerializeField] private bool showCropPreview = true;
[SerializeField] private Color borderColor = Color.green;
[SerializeField] private int borderWidth = 2;
[Header("=== 按鍵設定 ===")]
[Tooltip("截圖(可重複按覆蓋,不前進)")]
[SerializeField] private KeyCode captureKey = KeyCode.F12;
[Tooltip("重置同名計數(切到新頁面後按)")]
[SerializeField] private KeyCode resetCountKey = KeyCode.F9;
[Header("=== 裁切框微調 ===")]
[Tooltip("每次微調的像素數")]
[SerializeField] private int adjustStep = 5;
[Tooltip("快速微調的像素數(Shift加速)")]
[SerializeField] private int adjustStepFast = 20;
[Header("=== 狀態(自動更新)===")]
[SerializeField] private string lastPageTitle = "";
[SerializeField] private int samePageCount = 0;
[SerializeField] private int totalCaptured = 0;
private Texture2D borderTexture;
private PageController pageController;
private void Awake()
{
// 載入儲存的設定
LoadSettings();
// 找到 PageController
pageController = FindObjectOfType();
if (pageController == null)
Debug.LogError("❌ 找不到 PageController!請確認場景中有操作員選單。");
}
private void OnDestroy()
{
// 離開時自動儲存設定
SaveSettings();
}
private void OnApplicationQuit()
{
SaveSettings();
}
private void SaveSettings()
{
PlayerPrefs.SetInt("SSCrop_X", cropX);
PlayerPrefs.SetInt("SSCrop_Y", cropY);
PlayerPrefs.SetInt("SSCrop_W", cropWidth);
PlayerPrefs.SetInt("SSCrop_H", cropHeight);
PlayerPrefs.SetInt("SSCrop_BaseW", baseWidth);
PlayerPrefs.SetInt("SSCrop_BaseH", baseHeight);
PlayerPrefs.SetInt("SSCrop_Enabled", enableCrop ? 1 : 0);
PlayerPrefs.SetString("SSCrop_Path", basePath);
PlayerPrefs.Save();
}
private void LoadSettings()
{
if (PlayerPrefs.HasKey("SSCrop_X"))
{
cropX = PlayerPrefs.GetInt("SSCrop_X");
cropY = PlayerPrefs.GetInt("SSCrop_Y");
cropWidth = PlayerPrefs.GetInt("SSCrop_W");
cropHeight = PlayerPrefs.GetInt("SSCrop_H");
baseWidth = PlayerPrefs.GetInt("SSCrop_BaseW");
baseHeight = PlayerPrefs.GetInt("SSCrop_BaseH");
enableCrop = PlayerPrefs.GetInt("SSCrop_Enabled") == 1;
basePath = PlayerPrefs.GetString("SSCrop_Path");
Debug.Log($"✅ 已載入儲存的裁切設定: ({cropX},{cropY}) {cropWidth}x{cropHeight}");
}
}
private void Update()
{
// F12: 截圖
if (Input.GetKeyDown(captureKey))
{
CaptureCurrentPage();
}
// F9: 重置同名計數
if (Input.GetKeyDown(resetCountKey))
{
samePageCount = 0;
Debug.Log("🔄 同名計數已重置");
}
// Ctrl + 方向鍵:移動框位置
// Ctrl + Shift + 方向鍵:調整框大小
if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl))
{
bool shift = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
int step = shift ? adjustStepFast : adjustStep;
bool changed = false;
if (Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt))
{
// Ctrl + Alt + 方向鍵 = 調整大小
if (Input.GetKeyDown(KeyCode.RightArrow)) { cropWidth += step; changed = true; }
if (Input.GetKeyDown(KeyCode.LeftArrow)) { cropWidth -= step; changed = true; }
if (Input.GetKeyDown(KeyCode.DownArrow)) { cropHeight += step; changed = true; }
if (Input.GetKeyDown(KeyCode.UpArrow)) { cropHeight -= step; changed = true; }
}
else
{
// Ctrl + 方向鍵 = 移動位置
if (Input.GetKeyDown(KeyCode.RightArrow)) { cropX += step; changed = true; }
if (Input.GetKeyDown(KeyCode.LeftArrow)) { cropX -= step; changed = true; }
if (Input.GetKeyDown(KeyCode.DownArrow)) { cropY += step; changed = true; }
if (Input.GetKeyDown(KeyCode.UpArrow)) { cropY -= step; changed = true; }
}
if (changed)
{
// 確保不為負數
cropX = Mathf.Max(0, cropX);
cropY = Mathf.Max(0, cropY);
cropWidth = Mathf.Max(10, cropWidth);
cropHeight = Mathf.Max(10, cropHeight);
SaveSettings();
}
}
}
private void CaptureCurrentPage()
{
if (pageController == null || pageController.currentPage == null)
{
Debug.LogWarning("⚠️ 目前沒有頁面,無法截圖");
return;
}
// 讀取當前頁面標題
string title = pageController.currentPage.pageTitle;
if (string.IsNullOrEmpty(title))
{
title = pageController.currentPage.name; // fallback 用 GameObject 名
Debug.LogWarning($"⚠️ pageTitle 為空,使用 GameObject 名: {title}");
}
// 清理檔名(移除不合法字元)
string cleanTitle = CleanFileName(title);
// 判斷是否同頁面重複截圖
if (cleanTitle == lastPageTitle)
{
samePageCount++;
}
else
{
lastPageTitle = cleanTitle;
samePageCount = 0;
}
// 產生檔名
string fileName = samePageCount == 0 ? cleanTitle : $"{cleanTitle}_{samePageCount + 1}";
StartCoroutine(CaptureAndSave(fileName));
}
private System.Collections.IEnumerator CaptureAndSave(string fileName)
{
yield return new WaitForEndOfFrame();
int screenWidth = Screen.width;
int screenHeight = Screen.height;
Texture2D screenshot = new Texture2D(screenWidth, screenHeight, TextureFormat.RGB24, false);
screenshot.ReadPixels(new Rect(0, 0, screenWidth, screenHeight), 0, 0);
screenshot.Apply();
Texture2D finalImage;
if (enableCrop)
{
float scaleX = (float)screenWidth / (float)baseWidth;
float scaleY = (float)screenHeight / (float)baseHeight;
int actualCropX = Mathf.RoundToInt(cropX * scaleX);
int actualCropY = Mathf.RoundToInt((baseHeight - cropY - cropHeight) * scaleY);
int actualCropW = Mathf.RoundToInt(cropWidth * scaleX);
int actualCropH = Mathf.RoundToInt(cropHeight * scaleY);
actualCropX = Mathf.Clamp(actualCropX, 0, screenWidth - 1);
actualCropY = Mathf.Clamp(actualCropY, 0, screenHeight - 1);
actualCropW = Mathf.Min(actualCropW, screenWidth - actualCropX);
actualCropH = Mathf.Min(actualCropH, screenHeight - actualCropY);
finalImage = new Texture2D(actualCropW, actualCropH, TextureFormat.RGB24, false);
Color[] pixels = screenshot.GetPixels(actualCropX, actualCropY, actualCropW, actualCropH);
finalImage.SetPixels(pixels);
finalImage.Apply();
Destroy(screenshot);
}
else
{
finalImage = screenshot;
}
// 存檔(直接存到 basePath,不分子資料夾)
if (!Directory.Exists(basePath))
Directory.CreateDirectory(basePath);
byte[] bytes = finalImage.EncodeToPNG();
string filePath = Path.Combine(basePath, $"{fileName}.png");
File.WriteAllBytes(filePath, bytes);
Destroy(finalImage);
totalCaptured++;
Debug.Log($"📸 [{totalCaptured}] 已存: {fileName}.png ({bytes.Length / 1024}KB)");
}
// 即時顯示裁切框
private void OnGUI()
{
if (!showCropPreview || !enableCrop) return;
if (borderTexture == null)
{
borderTexture = new Texture2D(1, 1);
borderTexture.SetPixel(0, 0, borderColor);
borderTexture.Apply();
}
if (borderTexture.GetPixel(0, 0) != borderColor)
{
borderTexture.SetPixel(0, 0, borderColor);
borderTexture.Apply();
}
float scaleX = (float)Screen.width / (float)baseWidth;
float scaleY = (float)Screen.height / (float)baseHeight;
float drawX = cropX * scaleX;
float drawY = cropY * scaleY;
float drawW = cropWidth * scaleX;
float drawH = cropHeight * scaleY;
// 四條邊框
GUI.DrawTexture(new Rect(drawX, drawY, drawW, borderWidth), borderTexture);
GUI.DrawTexture(new Rect(drawX, drawY + drawH - borderWidth, drawW, borderWidth), borderTexture);
GUI.DrawTexture(new Rect(drawX, drawY, borderWidth, drawH), borderTexture);
GUI.DrawTexture(new Rect(drawX + drawW - borderWidth, drawY, borderWidth, drawH), borderTexture);
// 資訊
GUIStyle style = new GUIStyle(GUI.skin.label);
style.normal.textColor = borderColor;
style.fontSize = 12;
GUI.Label(new Rect(drawX + 4, drawY + 4, 300, 18), $"裁切: {cropWidth}x{cropHeight} 位置: ({cropX},{cropY})", style);
// 顯示目前頁面名稱
if (pageController != null && pageController.currentPage != null)
{
string title = pageController.currentPage.pageTitle;
if (!string.IsNullOrEmpty(title))
{
style.fontSize = 14;
GUI.Label(new Rect(drawX + 4, drawY + drawH - 22, 400, 20), $"📋 {title}", style);
}
}
}
private string CleanFileName(string name)
{
// 移除 Windows 檔名不允許的字元
char[] invalid = Path.GetInvalidFileNameChars();
foreach (char c in invalid)
name = name.Replace(c, '_');
return name.Trim();
}
[ContextMenu("重置所有計數")]
public void ResetAll()
{
samePageCount = 0;
totalCaptured = 0;
lastPageTitle = "";
Debug.Log("已重置所有計數");
}
[ContextMenu("儲存目前設定")]
public void ForceSave()
{
SaveSettings();
Debug.Log("✅ 設定已儲存");
}
[ContextMenu("清除儲存的設定")]
public void ClearSavedSettings()
{
PlayerPrefs.DeleteKey("SSCrop_X");
PlayerPrefs.DeleteKey("SSCrop_Y");
PlayerPrefs.DeleteKey("SSCrop_W");
PlayerPrefs.DeleteKey("SSCrop_H");
PlayerPrefs.DeleteKey("SSCrop_BaseW");
PlayerPrefs.DeleteKey("SSCrop_BaseH");
PlayerPrefs.DeleteKey("SSCrop_Enabled");
PlayerPrefs.DeleteKey("SSCrop_Path");
PlayerPrefs.Save();
Debug.Log("🗑️ 已清除儲存的設定");
}
}