Files
ichni_Official/Assets/Scripts/Game/GameElements/Essential/GameCamera.cs
SoulliesOfficial 8e4690c964 调整Bloom
2026-06-30 04:36:54 -04:00

147 lines
5.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using DG.Tweening;
using Ichni.RhythmGame.Beatmap;
using Ichni.UI;
using UniRx;
using UnityEngine;
using UnityEngine.Rendering.Universal;
using UnityEngine.Serialization;
namespace Ichni.RhythmGame
{
public partial class GameCamera : GameElement, IHaveTransformSubmodule, IHaveTimeDurationSubmodule
{
#region [] Camera View & Settings
public Camera cam;
//public Transform rotationPoint;
//public Transform positionPoint;
public Transform cameraTransform;
public CameraViewType cameraViewType;
public float perspectiveAngle;
public float orthographicSize;
public float perspectiveOffset;
public float zoomOffset; // 用于效果如CameraZoomEffect的临时视野偏移
public void RefreshFOV()
{
cam.fieldOfView = perspectiveAngle + perspectiveOffset + zoomOffset;
}
#endregion
#region [] Submodules & References
public TransformSubmodule transformSubmodule { get; set; }
public TimeDurationSubmodule timeDurationSubmodule { get; set; }
private static CameraManager cameraManager => GameManager.Instance.cameraManager;
#endregion
#region [] Lifecycle & Factory
public static GameCamera GenerateElement(string elementName, Guid id,
List<string> tags, bool isFirstGenerated, GameElement parentElement,
CameraViewType cameraViewType, float perspectiveAngle, float orthographicSize)
{
GameCamera gameCamera = Instantiate(GameManager.Instance.basePrefabs.gameCamera).GetComponent<GameCamera>();
gameCamera.Initialize(elementName, id, tags, isFirstGenerated, parentElement);
cameraManager.gameCamera = gameCamera;
gameCamera.parentElement = parentElement;
gameCamera.cameraViewType = cameraViewType;
gameCamera.cam.orthographic = cameraViewType == CameraViewType.Orthographic;
gameCamera.perspectiveAngle = perspectiveAngle;
gameCamera.orthographicSize = orthographicSize;
gameCamera.cameraTransform = gameCamera.transform;
float currentAspect = UIManager.GetScreenRatio();
float targetAspect = UIManager.StandardRatio;
if (currentAspect < targetAspect)
{
// 屏幕比较方 (如 4:3 平板),需要增加垂直 FOV 以保持 16:9 标准下的水平绝对视野
float hFovRad = 2.0f * Mathf.Atan(Mathf.Tan(perspectiveAngle * Mathf.Deg2Rad / 2.0f) * targetAspect);
float newVFovRad = 2.0f * Mathf.Atan(Mathf.Tan(hFovRad / 2.0f) / currentAspect);
// 设置 perspectiveOffset 以完美补足被裁切的空间
gameCamera.perspectiveOffset = (newVFovRad * Mathf.Rad2Deg) - perspectiveAngle;
}
else
{
// 屏幕比较长 (如 20:9 手机),维持原有垂直 FOV左右延展屏幕用于渲染环境背景
gameCamera.perspectiveOffset = 0f;
}
gameCamera.RefreshFOV();
return gameCamera;
}
public override void AfterInitialize()
{
base.AfterInitialize();
//gameCamera.GetComponent<UniversalAdditionalCameraData>().cameraStack.Add(cameraManager.uiCamera);
GameManager.Instance.backgroundController.backgroundCanvas.worldCamera = cam;
}
public override void SetDefaultSubmodules()
{
transformSubmodule = new TransformSubmodule(this);
}
#endregion
}
#region [] Enums
public partial class GameCamera
{
public enum CameraViewType
{
Perspective = 0,
Orthographic = 1
}
}
#endregion
#region [] Transform Observe & Update Logics
public partial class GameCamera
{
public void SetTransformObserver()
{
transformSubmodule.observer = Observable.EveryLateUpdate()
.Where(_=>GameManager.Instance.songPlayer.isUpdating)
.Subscribe(_ => UpdateTransform())
.AddTo(transformSubmodule.attachedGameElement);
}
public void UpdateTransform(bool refreshAll = true)
{
bool willRefresh = false;
if (!transformSubmodule.eulerAnglesOffsetLock && transformSubmodule.eulerAnglesDirtyMark)
{
transformSubmodule.currentEulerAngles = transformSubmodule.originalEulerAngles + transformSubmodule.eulerAnglesOffset;
transform.localEulerAngles = transformSubmodule.currentEulerAngles;
transformSubmodule.eulerAnglesDirtyMark = false;
willRefresh = true;
transformSubmodule.eulerAnglesOffset = Vector3.zero;
}
if (transformSubmodule.positionDirtyMark)
{
transformSubmodule.currentPosition = transformSubmodule.originalPosition + transformSubmodule.positionOffset;
transform.localPosition = transformSubmodule.currentPosition;
transformSubmodule.positionDirtyMark = false;
willRefresh = true;
transformSubmodule.positionOffset = Vector3.zero;
}
if (refreshAll && willRefresh)
{
Refresh();
}
}
}
#endregion
}