조준 시스템 개선
다른 블록에 의해 경로가 막힐 경우, 막은 블록을 하이라이트 + 조준과 공격 대상 선정 로직이 같아졌기 때문에 로직 통합
This commit is contained in:
@@ -34,6 +34,7 @@ public class PlayerNetworkController : NetworkBehaviour
|
||||
[SerializeField] private Sprite targetCrosshair;
|
||||
private RectTransform _crosshairRect;
|
||||
private MineableBlock _currentTargetBlock; // 현재 강조 중인 블록 저장
|
||||
private MineableBlock _lastHighlightedBlock;
|
||||
|
||||
private CharacterController _controller;
|
||||
private PlayerInputActions _inputActions;
|
||||
@@ -152,27 +153,11 @@ public class PlayerNetworkController : NetworkBehaviour
|
||||
{
|
||||
if (!IsOwner) return;
|
||||
|
||||
// 1. 마우스가 가리키는 월드상의 위치를 먼저 찾습니다.
|
||||
Ray mouseRay = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
|
||||
Vector3 worldAimPoint;
|
||||
|
||||
// 아주 멀리까지 레이를 쏴서 조준 방향을 결정합니다.
|
||||
if (Physics.Raycast(mouseRay, out RaycastHit mouseHit, 1000f, ~ignoreDuringAim))
|
||||
worldAimPoint = mouseHit.point;
|
||||
else
|
||||
worldAimPoint = mouseRay.GetPoint(100f);
|
||||
|
||||
// 2. 캐릭터 가슴 높이에서 조준점을 향하는 방향 계산
|
||||
Vector3 origin = transform.position + Vector3.up * 1.2f;
|
||||
Vector3 direction = (worldAimPoint - origin).normalized;
|
||||
|
||||
// 3. 캐릭터에서 해당 방향으로 SphereCast를 쏴서 가장 가까운 블록 하나를 찾습니다.
|
||||
// SphereCast는 가장 먼저 닿는 오브젝트 하나만 hit에 담습니다.
|
||||
if (Physics.SphereCast(origin, aimRadius, direction, out RaycastHit blockHit, attackRange, mineableLayer))
|
||||
// 현재 하이라이트 중인 블록이 있다면 그 녀석이 바로 공격 대상입니다!
|
||||
if (_lastHighlightedBlock != null)
|
||||
{
|
||||
if (blockHit.collider.TryGetComponent<NetworkObject>(out var netObj))
|
||||
if (_lastHighlightedBlock.TryGetComponent<NetworkObject>(out var netObj))
|
||||
{
|
||||
// 서버에 대미지 요청
|
||||
ApplyMiningDamageServerRpc(netObj.NetworkObjectId);
|
||||
}
|
||||
}
|
||||
@@ -286,48 +271,52 @@ public class PlayerNetworkController : NetworkBehaviour
|
||||
{
|
||||
if (!IsOwner || _crosshairRect == null) return;
|
||||
|
||||
// 1. [조준점 확보] 카메라 레이로 마우스가 가리키는 '실제 지점'을 찾습니다.
|
||||
Ray cameraRay = Camera.main.ScreenPointToRay(_crosshairRect.position);
|
||||
RaycastHit cameraHit;
|
||||
|
||||
// 지형이나 블록을 모두 검사하여 조준점을 잡습니다.
|
||||
bool hitSomething = Physics.Raycast(cameraRay, out cameraHit, 150f, ~ignoreDuringAim);
|
||||
Vector3 worldAimPoint = hitSomething ? cameraHit.point : cameraRay.GetPoint(100f);
|
||||
|
||||
// 2. [거리 및 방향 계산] 캐릭터 가슴에서 그 지점까지의 벡터를 구합니다.
|
||||
Vector3 origin = transform.position + Vector3.up * 1.2f;
|
||||
Vector3 toTarget = worldAimPoint - origin;
|
||||
float distToTarget = toTarget.magnitude;
|
||||
Vector3 direction = toTarget.normalized;
|
||||
|
||||
// 3. [대상 우선 판정]
|
||||
// 만약 카메라 레이가 '채광 가능한 블록'을 직접 때렸고, 그게 사거리 이내라면? -> 바로 타겟팅!
|
||||
bool isDirectHit = hitSomething && ((1 << cameraHit.collider.gameObject.layer) & mineableLayer) != 0;
|
||||
|
||||
RaycastHit finalHit;
|
||||
bool hasValidTarget = false;
|
||||
|
||||
if (isDirectHit && distToTarget <= attackRange)
|
||||
{
|
||||
// 마우스가 직접 블록을 가리키고 사거리 내에 있는 경우
|
||||
finalHit = cameraHit;
|
||||
hasValidTarget = true;
|
||||
}
|
||||
// 1. 카메라 레이로 조준점 계산 (플레이어 몸통 무시)
|
||||
Ray aimRay = Camera.main.ScreenPointToRay(_crosshairRect.position);
|
||||
Vector3 worldAimPoint;
|
||||
if (Physics.Raycast(aimRay, out RaycastHit mouseHit, 100f, ~ignoreDuringAim))
|
||||
worldAimPoint = mouseHit.point;
|
||||
else
|
||||
worldAimPoint = aimRay.GetPoint(50f);
|
||||
|
||||
// 2. 캐릭터 가슴에서 조준점을 향하는 방향 계산
|
||||
Vector3 origin = transform.position + Vector3.up * 1.2f;
|
||||
Vector3 direction = (worldAimPoint - origin).normalized;
|
||||
|
||||
// 자기 자신 충돌 방지용 오프셋
|
||||
Vector3 rayStart = origin + direction * 0.4f;
|
||||
|
||||
// 3. [중요] 실제 공격과 동일한 SphereCast 실행
|
||||
RaycastHit blockHit;
|
||||
bool hasTarget = Physics.SphereCast(rayStart, aimRadius, direction, out blockHit, attackRange - 0.4f, mineableLayer);
|
||||
|
||||
// 4. 하이라이트 대상 업데이트
|
||||
MineableBlock currentTarget = null;
|
||||
if (hasTarget)
|
||||
{
|
||||
// 마우스가 허공을 보거나 너무 먼 곳을 볼 때만 '범위 탐색(SphereCast)'을 수행합니다.
|
||||
float searchDist = Mathf.Min(distToTarget, attackRange);
|
||||
Vector3 rayStart = origin + direction * 0.4f;
|
||||
hasValidTarget = Physics.SphereCast(rayStart, aimRadius, direction, out finalHit, searchDist - 0.4f, mineableLayer);
|
||||
currentTarget = blockHit.collider.GetComponentInParent<MineableBlock>();
|
||||
}
|
||||
|
||||
// 4. 디버그 및 시각화 업데이트
|
||||
_debugOrigin = origin;
|
||||
_debugDir = direction;
|
||||
_debugHit = hasValidTarget;
|
||||
_debugDist = hasValidTarget ? Vector3.Distance(origin, finalHit.point) : Mathf.Min(distToTarget, attackRange);
|
||||
// 대상이 바뀌었을 때만 아웃라인 갱신 (최적화)
|
||||
if (_lastHighlightedBlock != currentTarget)
|
||||
{
|
||||
if (_lastHighlightedBlock != null) _lastHighlightedBlock.SetHighlight(false);
|
||||
if (currentTarget != null) currentTarget.SetHighlight(true);
|
||||
_lastHighlightedBlock = currentTarget;
|
||||
}
|
||||
|
||||
UpdateBlockVisuals(hasValidTarget, finalHit);
|
||||
// 기즈모 디버그 데이터 동기화
|
||||
_debugOrigin = rayStart;
|
||||
_debugDir = direction;
|
||||
_debugHit = hasTarget;
|
||||
_debugDist = hasTarget ? blockHit.distance : (attackRange - 0.4f);
|
||||
|
||||
// 크로스헤어 이미지 교체
|
||||
if (crosshairUI != null)
|
||||
{
|
||||
crosshairUI.sprite = hasTarget ? targetCrosshair : idleCrosshair;
|
||||
crosshairUI.color = hasTarget ? Color.green : Color.white;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateBlockVisuals(bool hasTarget, RaycastHit hit)
|
||||
|
||||
Reference in New Issue
Block a user