Project_WL/Assets/Script/Util/RealCamera.cs

389 lines
14 KiB
C#
Raw Normal View History

using System;
2024-12-15 01:39:39 +00:00
using System.Collections.Generic;
2024-12-23 00:36:04 +00:00
using UnityEngine;
using Random = UnityEngine.Random;
[Serializable]
public class cCamData
{
public float minDistance = 1.5f;
public float maxDistance = 1.6f;
public float DistanceUp = 1f;
public float cameraHeight = 78f;
}
2024-12-15 01:39:39 +00:00
public class RealCamera : MyCoroutine
{
[Header("Camera Properties")]
private float DistanceAway; //how far the camera is from the player.
public float minDistance = 1; //min camera distance
public float maxDistance = 2; //max camera distance
public float DistanceUp = -2; //how high the camera is above the player
public float smooth = 4.0f; //how smooth the camera moves into place
public float rotateAround = 70f; //the angle at which you will rotate the camera (on an axis)
public Vector3 m_LookAt = Vector3.up;
public Vector3 m_BackOffSet = new Vector3(0f, 0.1f, -0.2f);
[HideInInspector] public bool m_BackMove;
[Header("Player to follow")]
public Transform target; //the target the camera follows
Actor m_Target;
bool isTarget;
2024-12-15 01:39:39 +00:00
[Header("Layer(s) to include")]
public LayerMask CamOcclusion; //the layers that will be affected by collision
[Header("Map coordinate script")]
// public worldVectorMap wvm;
public float cameraHeight = 55f;
public float cameraPan = 0f;
float camRotateSpeed = 180f;
Vector3 camPosition;
Vector3 camMask;
private float HorizontalAxis, VerticalAxis;
int CamStatus = 1; // 0 초기, 1 평소, 2 followtarget 오른쪽뷰, 3 followtarget 탑뷰(고정), 4 보스전
2024-12-15 01:39:39 +00:00
float DragEndTime;
GameObject godummy, gowitch;
List<Transform> list_tfCamactionTarget = new List<Transform>();
bool islockTarget;
Transform tf_lockTarget;
2025-05-02 22:12:43 +00:00
Actor m_followTarget;
WL 리뉴얼 세션 2026-09-06~07 (#760~#800) — 전투·배경·UI·타격감 (조직 PD 로그 #746~#800 · 대화로그 §14~§24) - 전투: Knight@Attack1~3_S 3콤보(4 컨트롤러·클래스별 서브클립) · 타겟팅 4규칙(정면 우선·재타겟·즉시 공격·어그로 금지 · WLTargetingSettings) · 대쉬 후 공격(Stander@Chase_Start · DashDriver · 5 m · 사정거리+0.8 · 근거리 적 우선) · 공격 이동 FrameTable(발 접지 실측 표 · AttackRootMotion) · 충돌 반경/투사체 0.3 배(WLCollisionTuning) · 무적(임시)·펫 금지(WLGameplaySettings) - 검기: NamuFX Slash_B 배리언트 Effect_WLSwingArc 원 피팅 정합 배치 + 캘리브레이션(SlashArcMeasure · SlashTrailSettings) · 찌르기 Effect_WLStab 대기 · 램프 리본(BladeTrail · WL_BladeRibbon.shader · T_WL_BladeRibbonRamp) 보존(drawRibbon 0) - 타격감: Assets/WL/Feel(WLHitFeel · 히트스톱 0.03 · 셰이크 0.10 m · 몹 펀치 1.12 · Actor.Get_Damage 훅 1줄 · 원본 RealCamera 셰이크 결함 대체) - 배경/맵: LMHPOLY Demo_01~10 → WL_Nature01~10(프리팹·씬·NavMesh·스포너·BattleMapConfig) · 물(ToonWaterU) · 포스트 블룸 0.9/0.3 · 잔디(BruteForce·드레싱) 제거 · 마젠타 머티리얼 URP 변환 - UI: 세로 HUD(WL_HUD · 하단 5메뉴 폭 전체 · 채팅/전투 패드 숨김 · WLIngameUiOverride) · Title/TitleInfo 1080×1920 Expand + 배경 높이 fit(WLBackgroundFit) · 로딩 SortOrder_5(WLRawImageAspectSync · 초점표 8장) · Loading1~8 ASTC 6×6 - 도구: AgentScripts/*(LightProbe · WL_MapSwitch · WL760~WL800 프로브/집행/검증 · 상단 사용법 주석) · 에디터 락 프로토콜 파일(staging) - 제외(별도 커밋 예정): Assets/LMHPOLY(703 MB) · Assets/Feel(422 MB) · Assets/Shinabro(300 MB) — 에셋 스토어/구 WL 팩 원본 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-06 23:24:25 +00:00
// 이동 방향 리드/피치 (PD #755) — 값의 SOT = Resources/WL/CameraLeadSettings.asset.
// 에셋이 없거나 enabled=false 면 아래 세 출력이 전부 0 → 기존 동작과 완전히 동일하다.
readonly CameraMoveLead m_MoveLead = new CameraMoveLead();
public CameraMoveLead Get_MoveLead() { return m_MoveLead; }
public cCamData[] arr_cCamData; // 0 일반, 1 보스
2024-12-15 01:39:39 +00:00
2025-05-22 01:35:48 +00:00
void Init_Cam()
{
int index = islockTarget ? 1 : 0;
Set_DistanceUp(false);
minDistance = arr_cCamData[index].minDistance;
VerticalAxis = maxDistance = arr_cCamData[index].maxDistance;
cameraHeight = arr_cCamData[index].cameraHeight;
}
public void Add_Rot(float rot) { rotateAround += rot; }
public void Set_Rot(float rot) { rotateAround = rot; }
2024-12-15 01:39:39 +00:00
public bool IsEnter() { return CamStatus == 0; }
public void Set_Target(Transform _target)
2024-12-15 01:39:39 +00:00
{
2024-12-23 00:36:04 +00:00
target = _target;
isTarget = target;
if (isTarget)
{
m_Target = target.GetComponent<Actor>();
Add_CamActionTarget(_target);
}
}
public void Set_Target(Transform _target, float _camrot)
{
Set_Target(_target);
CamStatus = 0;
2024-12-23 00:36:04 +00:00
rotateAround = _camrot;
2025-05-22 01:35:48 +00:00
Init_Cam();
2024-12-15 01:39:39 +00:00
}
2025-01-05 02:37:53 +00:00
public void Set_DistanceUp(bool vertical)
{
2025-08-13 04:59:42 +00:00
//DistanceUp = vertical ? 0f : arr_cCamData[islockTarget ? 1 : 0].DistanceUp;
DistanceUp = vertical ? arr_cCamData[0].DistanceUp : arr_cCamData[islockTarget ? 1 : 0].DistanceUp;
2025-01-05 02:37:53 +00:00
}
2024-12-15 01:39:39 +00:00
public void Set_InsideBuilding(bool _active)
{
if (_active)
{
maxDistance = minDistance = 2f;
DistanceUp = 1.5f;
cameraHeight = 25f;
}
else
{
2025-05-22 01:35:48 +00:00
Init_Cam();
2024-12-15 01:39:39 +00:00
}
}
2025-05-02 22:12:43 +00:00
public void Set_FollowTarget(Actor target)
{
m_followTarget = target;
CamStatus = target ? 2 : 1;
}
2025-05-05 01:43:26 +00:00
public void Set_TopView(Actor target)
{
m_followTarget = target;
CamStatus = target ? 3 : 1;
}
2024-12-15 01:39:39 +00:00
public void Add_CamActionTarget(Transform _target) { list_tfCamactionTarget.Add(_target); }
public void Set_LockTarget(Transform locktarget)
{
tf_lockTarget = locktarget;
islockTarget = tf_lockTarget;
2025-05-22 01:35:48 +00:00
Init_Cam();
}
2024-12-15 01:39:39 +00:00
public void Set_TargetShow(Transform _target)
{
if (CamStatus != 0 && isTarget)
2024-12-15 01:39:39 +00:00
{
// 매개변수 타겟을 보게 카메라 회전
Set_CamDummy(_target);
2024-12-15 01:39:39 +00:00
Set_Coroutine(() => { rotateAround = godummy.transform.eulerAngles.y - 45f; }, 0.1f);
}
}
void Set_CamDummy(Transform _target)
{
if (godummy == null) godummy = new GameObject("CamDummy");
godummy.transform.position = target.position;
godummy.transform.LookAt(_target);
}
2024-12-15 01:39:39 +00:00
public void Set_Axis(bool _horizontal, float _value)
{
DragEndTime = 1f;
if (_horizontal) HorizontalAxis = _value;
else VerticalAxis = _value;
//NewGameUI.Ins.m_GuideQuestUI.Add_GuideQuest(ePurpose.ScreenRot);
2024-12-15 01:39:39 +00:00
}
public void Set_AutoCam_byMyPC()
{
if (DragEndTime <= 0f)
{
if (DSUtil.CheckNull(gowitch)) gowitch = new GameObject("witchDummy");
2024-12-15 01:39:39 +00:00
gowitch.transform.position = MyValue.MyPC.Get_position() + MyValue.MyPC.transform.forward;
Set_TargetShow(gowitch.transform);
}
}
2025-05-04 04:52:26 +00:00
public void MoveCam_TargetBack(Vector3 targetpos)
{
transform.position = targetpos;
2025-05-05 00:45:45 +00:00
RotateCam_TargetBack();
2025-05-04 04:52:26 +00:00
}
2025-05-05 00:45:45 +00:00
public void RotateCam_TargetBack() { rotateAround = target.eulerAngles.y - 45f; }
2024-12-15 01:39:39 +00:00
// Use this for initialization
void Start()
{
//the statement below automatically positions the camera behind the target.
//rotateAround = target.eulerAngles.y - 45f;
}
void LateUpdate()
{
2025-05-05 01:43:26 +00:00
Shaking();
2024-12-15 01:39:39 +00:00
if (DragEndTime > 0f) DragEndTime -= Time.deltaTime;
if (!isTarget) return;
//if (m_Target.Get_CurAnim() == eAnim.Attack) return;
2024-12-15 01:39:39 +00:00
// 캐릭터의 이동 방향 계산
//Vector3 direction = target.position - previousPosition;
2024-12-15 01:39:39 +00:00
//// 이동 방향이 존재할 때 캐릭터가 보는 방향으로 카메라 회전
//if (direction.sqrMagnitude > 0.01f)
//{
// // 캐릭터가 움직이고 있는 방향으로 회전 목표 각도 계산
// float targetRotationAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg;
// // 현재 회전 각도에서 목표 회전 각도로 부드럽게 보간
// rotateAround = Mathf.LerpAngle(rotateAround, targetRotationAngle, rotationSpeed * Time.deltaTime);
//}
// 카메라를 설정된 로직에 따라 업데이트
if (CamStatus == 0)
{
var camTarget = list_tfCamactionTarget[0];
Vector3 lTargetDir = camTarget.position - transform.position;
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(lTargetDir + m_LookAt), Time.deltaTime * 2.5f);
Vector3 targetOffset = target.position;
Quaternion rotation = Quaternion.Euler(cameraHeight, rotateAround, cameraPan);
Vector3 vectorMask = Vector3.one;
Vector3 rotateVector = rotation * vectorMask;
DistanceAway = Mathf.Clamp(DistanceAway += VerticalAxis, minDistance, maxDistance);
camPosition = targetOffset + Vector3.up * DistanceUp - rotateVector * DistanceAway;
//transform.position = Vector3.Lerp(transform.position, camPosition, Time.deltaTime * 2.5f);
transform.position = Vector3.Lerp(transform.position, camPosition, 1f); // 즉시 이동
2024-12-15 01:39:39 +00:00
if (Vector3.Distance(transform.position, camPosition) < 0.05f)
{
list_tfCamactionTarget.RemoveAt(0);
if (list_tfCamactionTarget.Count <= 0)
{
CamStatus = 1;
Start_Game();
}
}
}
else if (CamStatus == 1)
Update_Cam();
2025-05-02 22:12:43 +00:00
else if (CamStatus == 2)
{
if (m_followTarget == null) return;
2025-05-05 01:43:26 +00:00
// 팔로우 타겟 기준 위치 설정
2025-05-02 22:12:43 +00:00
Vector3 followOffset = m_followTarget.transform.position + m_followTarget.transform.right * CamStatus2_x +
Vector3.up * CamStatus2_up;
// 카메라 위치 보간
transform.position = Vector3.Lerp(transform.position, followOffset, Time.deltaTime * 5f);
// 타겟의 머리 또는 약간 위를 보도록 설정
Vector3 lookTarget = m_followTarget.transform.position + Vector3.up * CamStatus2_up;
// 회전도 자연스럽게 보간
Quaternion targetRot = Quaternion.LookRotation(lookTarget - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, Time.deltaTime * 5f);
}
2025-05-05 01:43:26 +00:00
else if (CamStatus == 3)
{
transform.position = m_followTarget.Get_position() + Vector3.up * 10f;
transform.eulerAngles = new Vector3(90f, transform.eulerAngles.y);
}
2024-12-15 01:39:39 +00:00
}
2025-05-22 01:35:48 +00:00
public float CamStatus2_x = 4f; // 특정 스킬뷰
public float CamStatus2_up = 1.4f; // 특정 스킬뷰
2024-12-15 01:39:39 +00:00
void Start_Game()
{
ActorInfo.Ins.All_Stop(false);
2024-12-15 01:39:39 +00:00
Time.timeScale = MyValue.Get_GameSpeed();
DungeonInfo.Ins.Start_Dungeon(true);
2024-12-15 01:39:39 +00:00
}
void Update_Cam()
{
WL 리뉴얼 세션 2026-09-06~07 (#760~#800) — 전투·배경·UI·타격감 (조직 PD 로그 #746~#800 · 대화로그 §14~§24) - 전투: Knight@Attack1~3_S 3콤보(4 컨트롤러·클래스별 서브클립) · 타겟팅 4규칙(정면 우선·재타겟·즉시 공격·어그로 금지 · WLTargetingSettings) · 대쉬 후 공격(Stander@Chase_Start · DashDriver · 5 m · 사정거리+0.8 · 근거리 적 우선) · 공격 이동 FrameTable(발 접지 실측 표 · AttackRootMotion) · 충돌 반경/투사체 0.3 배(WLCollisionTuning) · 무적(임시)·펫 금지(WLGameplaySettings) - 검기: NamuFX Slash_B 배리언트 Effect_WLSwingArc 원 피팅 정합 배치 + 캘리브레이션(SlashArcMeasure · SlashTrailSettings) · 찌르기 Effect_WLStab 대기 · 램프 리본(BladeTrail · WL_BladeRibbon.shader · T_WL_BladeRibbonRamp) 보존(drawRibbon 0) - 타격감: Assets/WL/Feel(WLHitFeel · 히트스톱 0.03 · 셰이크 0.10 m · 몹 펀치 1.12 · Actor.Get_Damage 훅 1줄 · 원본 RealCamera 셰이크 결함 대체) - 배경/맵: LMHPOLY Demo_01~10 → WL_Nature01~10(프리팹·씬·NavMesh·스포너·BattleMapConfig) · 물(ToonWaterU) · 포스트 블룸 0.9/0.3 · 잔디(BruteForce·드레싱) 제거 · 마젠타 머티리얼 URP 변환 - UI: 세로 HUD(WL_HUD · 하단 5메뉴 폭 전체 · 채팅/전투 패드 숨김 · WLIngameUiOverride) · Title/TitleInfo 1080×1920 Expand + 배경 높이 fit(WLBackgroundFit) · 로딩 SortOrder_5(WLRawImageAspectSync · 초점표 8장) · Loading1~8 ASTC 6×6 - 도구: AgentScripts/*(LightProbe · WL_MapSwitch · WL760~WL800 프로브/집행/검증 · 상단 사용법 주석) · 에디터 락 프로토콜 파일(staging) - 제외(별도 커밋 예정): Assets/LMHPOLY(703 MB) · Assets/Feel(422 MB) · Assets/Shinabro(300 MB) — 에셋 스토어/구 WL 팩 원본 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-06 23:24:25 +00:00
m_MoveLead.Evaluate(target, m_Target, transform, DistanceAway, cameraHeight,
out Vector3 leadOffset, out float pitchAdd, out float yawAdd);
Vector3 targetOffset = target.position + leadOffset;
Quaternion rotation = Quaternion.Euler(cameraHeight + pitchAdd, rotateAround + yawAdd, cameraPan);
2024-12-15 01:39:39 +00:00
Vector3 vectorMask = Vector3.one;
Vector3 rotateVector = rotation * vectorMask;
camPosition = targetOffset + Vector3.up * DistanceUp - rotateVector * DistanceAway;
camMask = targetOffset + Vector3.up * DistanceUp - rotateVector * DistanceAway;
//occludeRay(ref targetOffset);
transform.position = Vector3.Lerp(transform.position, camPosition, Time.deltaTime * smooth);
2024-12-15 01:39:39 +00:00
if (m_BackMove)
{
Vector3 backOffsetDirection = -transform.forward.normalized * m_BackOffSet.z;
transform.position += new Vector3(backOffsetDirection.x, 0f, backOffsetDirection.z);
}
if (islockTarget)
{
Set_CamDummy(tf_lockTarget);
rotateAround = godummy.transform.eulerAngles.y - 45f;
}
WL 리뉴얼 세션 2026-09-06~07 (#760~#800) — 전투·배경·UI·타격감 (조직 PD 로그 #746~#800 · 대화로그 §14~§24) - 전투: Knight@Attack1~3_S 3콤보(4 컨트롤러·클래스별 서브클립) · 타겟팅 4규칙(정면 우선·재타겟·즉시 공격·어그로 금지 · WLTargetingSettings) · 대쉬 후 공격(Stander@Chase_Start · DashDriver · 5 m · 사정거리+0.8 · 근거리 적 우선) · 공격 이동 FrameTable(발 접지 실측 표 · AttackRootMotion) · 충돌 반경/투사체 0.3 배(WLCollisionTuning) · 무적(임시)·펫 금지(WLGameplaySettings) - 검기: NamuFX Slash_B 배리언트 Effect_WLSwingArc 원 피팅 정합 배치 + 캘리브레이션(SlashArcMeasure · SlashTrailSettings) · 찌르기 Effect_WLStab 대기 · 램프 리본(BladeTrail · WL_BladeRibbon.shader · T_WL_BladeRibbonRamp) 보존(drawRibbon 0) - 타격감: Assets/WL/Feel(WLHitFeel · 히트스톱 0.03 · 셰이크 0.10 m · 몹 펀치 1.12 · Actor.Get_Damage 훅 1줄 · 원본 RealCamera 셰이크 결함 대체) - 배경/맵: LMHPOLY Demo_01~10 → WL_Nature01~10(프리팹·씬·NavMesh·스포너·BattleMapConfig) · 물(ToonWaterU) · 포스트 블룸 0.9/0.3 · 잔디(BruteForce·드레싱) 제거 · 마젠타 머티리얼 URP 변환 - UI: 세로 HUD(WL_HUD · 하단 5메뉴 폭 전체 · 채팅/전투 패드 숨김 · WLIngameUiOverride) · Title/TitleInfo 1080×1920 Expand + 배경 높이 fit(WLBackgroundFit) · 로딩 SortOrder_5(WLRawImageAspectSync · 초점표 8장) · Loading1~8 ASTC 6×6 - 도구: AgentScripts/*(LightProbe · WL_MapSwitch · WL760~WL800 프로브/집행/검증 · 상단 사용법 주석) · 에디터 락 프로토콜 파일(staging) - 제외(별도 커밋 예정): Assets/LMHPOLY(703 MB) · Assets/Feel(422 MB) · Assets/Shinabro(300 MB) — 에셋 스토어/구 WL 팩 원본 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-06 23:24:25 +00:00
transform.LookAt(target.position + leadOffset + m_LookAt);
2024-12-15 01:39:39 +00:00
#region wrap the cam orbit rotation
if (rotateAround > 360) rotateAround = 0f;
else if (rotateAround < 0f) rotateAround += 360f;
2024-12-15 01:39:39 +00:00
#endregion
rotateAround += HorizontalAxis * camRotateSpeed * Time.deltaTime;
if (HorizontalAxis >= -0.1f || HorizontalAxis <= 0.1f) HorizontalAxis = 0f;
//DistanceUp = Mathf.Clamp(DistanceUp += VerticalAxis, -0.79f, 2.3f);
DistanceAway = Mathf.Clamp(DistanceAway += VerticalAxis, minDistance, maxDistance);
if (VerticalAxis >= -0.1f || VerticalAxis <= 0.1f)
VerticalAxis = 0f;
}
void occludeRay(ref Vector3 targetFollow)
{
#region prevent wall clipping
//declare a new raycast hit.
//linecast from your player (targetFollow) to your cameras mask (camMask) to find collisions.
if (Physics.Linecast(targetFollow, camMask, out RaycastHit wallHit, CamOcclusion))
{
if (wallHit.collider.tag == "Untagged" && wallHit.collider.GetComponent<Actor>() == null &&
(wallHit.collider.GetComponent<BoxCollider>() != null || wallHit.collider.GetComponent<MeshCollider>() != null || wallHit.collider.GetComponent<TerrainCollider>() != null))
{
//the smooth is increased so you detect geometry collisions faster.
smooth = 10f;
2024-12-15 01:39:39 +00:00
//the x and z coordinates are pushed away from the wall by hit.normal.
//the y coordinate stays the same.
camPosition = new Vector3(wallHit.point.x + wallHit.normal.x * 0.5f, camPosition.y, wallHit.point.z + wallHit.normal.z * 0.5f);
}
}
else
smooth = 4f;
2024-12-15 01:39:39 +00:00
#endregion
}
#region
[Header("Camera Shake")]
float m_shakeDuration = 0.3f;
float m_shakeMagnitude = 0.1f;
public AnimationCurve shakeCurve = AnimationCurve.EaseInOut(0, 1, 1, 0);
private float m_shakeTimer = 0f;
private Vector3 originalPosition;
int curShakeType;
/// <summary>
/// shaketype : 0 약하게 1 보통 2 세게
/// </summary>
public void ShakeCamera(int shaketype)
{
2025-05-05 01:43:26 +00:00
//if (CamStatus == 3) return;
if (curShakeType == shaketype && m_shakeTimer > 0f)
return;
curShakeType = shaketype;
switch (shaketype)
{
default:
case 0: // 약하게
m_shakeMagnitude = 0.05f;
m_shakeDuration = 0.2f;
m_shakeTimer = 0.15f;
break;
case 1: // 보통
m_shakeMagnitude = 0.1f;
m_shakeDuration = 0.3f;
m_shakeTimer = 0.25f;
break;
case 2: // 세게
m_shakeMagnitude = 0.2f;
m_shakeDuration = 0.4f;
m_shakeTimer = 0.5f;
break;
}
originalPosition = transform.localPosition;
}
void Shaking()
{
if (m_shakeTimer > 0f)
{
float percentComplete = 1 - (m_shakeTimer / m_shakeDuration);
float damper = shakeCurve.Evaluate(percentComplete);
Vector3 shakeOffset = Random.insideUnitSphere * m_shakeMagnitude * damper;
2025-05-01 22:41:51 +00:00
//shakeOffset.y = 0; // 수직 흔들림 제거
transform.localPosition = originalPosition + shakeOffset;
m_shakeTimer -= Time.deltaTime;
if (m_shakeTimer <= 0f)
StopShake();
}
}
public void StopShake()
{
m_shakeTimer = 0f;
transform.localPosition = originalPosition;
}
#endregion
2024-12-15 01:39:39 +00:00
}