2026-03-31 물체 상호작용
This commit is contained in:
8
Assets/02_Scripts/Interactions.meta
Normal file
8
Assets/02_Scripts/Interactions.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4a0919c1b07731240838f8afcc713de2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/02_Scripts/Interactions/IInteractable.cs
Normal file
8
Assets/02_Scripts/Interactions/IInteractable.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using UnityEngine;
|
||||
|
||||
public interface IInteractable
|
||||
{
|
||||
public void InteractOpen();
|
||||
public void InteractClose();
|
||||
public void InteractExec(PlayerCharacterController player);
|
||||
}
|
||||
2
Assets/02_Scripts/Interactions/IInteractable.cs.meta
Normal file
2
Assets/02_Scripts/Interactions/IInteractable.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a75892d4d295c54e88d2933e38776c4
|
||||
37
Assets/02_Scripts/Interactions/InteractableSit.cs
Normal file
37
Assets/02_Scripts/Interactions/InteractableSit.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
|
||||
public class InteractableSit : MonoBehaviour,IInteractable
|
||||
{
|
||||
private bool interactionOnOff = false;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if(interactionOnOff)
|
||||
{
|
||||
//메인카메라를 기준으로 좌표 변환
|
||||
Vector3 pos = Camera.main.WorldToScreenPoint(transform.position + Vector3.up * 0.5f);
|
||||
|
||||
//변환된 좌표로 InteractionBox 이동
|
||||
GameManager.Instance.InGameUI.Interaction.UpdateSitBoxPos(pos);
|
||||
}
|
||||
}
|
||||
|
||||
public void InteractOpen()
|
||||
{
|
||||
interactionOnOff = true;
|
||||
GameManager.Instance.InGameUI.Interaction.OnOffSitBox(true);
|
||||
}
|
||||
|
||||
public void InteractClose()
|
||||
{
|
||||
interactionOnOff = false;
|
||||
GameManager.Instance.InGameUI.Interaction.OnOffSitBox(false);
|
||||
}
|
||||
|
||||
public void InteractExec(PlayerCharacterController player)
|
||||
{
|
||||
player.transform.position = gameObject.transform.position;
|
||||
player.transform.rotation = gameObject.transform.rotation;
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/Interactions/InteractableSit.cs.meta
Normal file
2
Assets/02_Scripts/Interactions/InteractableSit.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36992c9e66ae1344bb485ca8bce2aa5b
|
||||
@@ -42,7 +42,6 @@ public class Item : ScriptableObject
|
||||
|
||||
//ItemEffectType.RECOVERY_HP
|
||||
public float RecoveryHP;
|
||||
public float RecoveryHPTime;
|
||||
//ItemEffectType.INTERVAL_DAMAGE 일 경우
|
||||
public float IntervalDamage;
|
||||
public float IntervalDamageTime;
|
||||
|
||||
@@ -25,6 +25,7 @@ public class InputManager : MonoBehaviour
|
||||
public event Action<InputState> OnDodgeEvent;
|
||||
public event Action OnNormalAttackEvent;
|
||||
public event Action OnHeavyAttackEvent;
|
||||
public event Action OnInteractionEvent;
|
||||
|
||||
|
||||
//키조작
|
||||
@@ -34,6 +35,7 @@ public class InputManager : MonoBehaviour
|
||||
public event Action OnKeyDown_IKeyEvent;
|
||||
|
||||
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance == null)
|
||||
@@ -102,7 +104,11 @@ public void SetCharacterInputMap(string mapName)
|
||||
BindActionCharacter("Dodge", OnDodge);
|
||||
BindActionCharacter("NormalAttack", OnNormalAttack);
|
||||
BindActionCharacter("HeavyAttack", OnHeavyAttack);
|
||||
|
||||
BindActionCharacter("Interaction", OnInteraction);
|
||||
|
||||
BindActionCharacter("OnkeyDown_IKey", OnKeyDown_IKey);
|
||||
|
||||
|
||||
_characterInputActionMap.Disable();
|
||||
|
||||
@@ -211,6 +217,12 @@ private void OnHeavyAttack(InputAction.CallbackContext ctx)
|
||||
{
|
||||
OnHeavyAttackEvent?.Invoke();
|
||||
}
|
||||
|
||||
private void OnInteraction(InputAction.CallbackContext ctx)
|
||||
{
|
||||
if (ctx.started)
|
||||
OnInteractionEvent?.Invoke();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 키별 조작
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System.Collections;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Unity.VisualScripting;
|
||||
using Unity.VisualScripting.Antlr3.Runtime;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
@@ -13,22 +15,40 @@ public void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
||||
|
||||
public void ItemUse(ItemInstance item)
|
||||
{
|
||||
Debug.Log("아이템 사용");
|
||||
|
||||
switch(item.Data.ItemEffectType)
|
||||
{
|
||||
case ItemEffectType.RECOVERY_HP:
|
||||
{
|
||||
Debug.Log("HP회복 작동!!");
|
||||
//RecoveryHPHealthEffect(GameManager.Instance.Level.CurrentCharacter.GetComponent<Health>(), item.Data.IntervalDamage, item.Data.IntervalDamageTime, item.Data.ItemEffectVisual);
|
||||
Debug.Log($"전 HP : {GameManager.Instance.Level.CurrentCharacter.GetComponent<Health>().CurrentHP}");
|
||||
RecoveryHPHealthEffect(GameManager.Instance.Level.CurrentCharacter.GetComponent<Health>(), item.Data.RecoveryHP, item.Data.ItemEffectVisual);
|
||||
Debug.Log($"후 HP : {GameManager.Instance.Level.CurrentCharacter.GetComponent<Health>().CurrentHP}");
|
||||
}
|
||||
break;
|
||||
case ItemEffectType.INTERVAL_DAMAGE:
|
||||
{
|
||||
Debug.Log("틱데미지 아이템 타입임");
|
||||
|
||||
IntervalDamageHealthEffect(GameManager.Instance.Level.CurrentCharacter.GetComponent<Health>(), item.Data.IntervalDamage, item.Data.IntervalDamageTime, item.Data.ItemEffectVisual);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void RecoveryHPHealthEffect(Health health,float recoveryHP,GameObject itemEffectVisual)
|
||||
{
|
||||
PlayerHealth playerHealth = health as PlayerHealth;
|
||||
if (playerHealth != null)
|
||||
{
|
||||
GameObject fx_Visual = Instantiate(itemEffectVisual, playerHealth.transform); // health의 자식으로 이펙트 생성
|
||||
fx_Visual.transform.localPosition = new Vector3(0, 1.5f, 0);
|
||||
playerHealth.ChangeHP(Mathf.Clamp(playerHealth.CurrentHP + Mathf.FloorToInt(recoveryHP), 0, playerHealth.Pstat.MaxHp)); //소수점 전부 버림
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void IntervalDamageHealthEffect(Health health,float damage,float time,GameObject itemEffectVisual)
|
||||
{
|
||||
IntervalDamage(health, damage,time, itemEffectVisual);
|
||||
@@ -37,17 +57,39 @@ public void IntervalDamageHealthEffect(Health health,float damage,float time,Gam
|
||||
//일정 시간 동안 틱대미지 일으키는 함수
|
||||
public async void IntervalDamage(Health health, float damage,float time, GameObject itemEffectVisual)
|
||||
{
|
||||
// 유니티 오브젝트 자체의 CancellationToken 가져오기 (오브젝트 파괴 시 자동 취소)
|
||||
CancellationToken token = health.destroyCancellationToken;
|
||||
|
||||
GameObject fx_Visual = Instantiate(itemEffectVisual, health.transform); // health의 자식으로 이펙트 생성
|
||||
fx_Visual.transform.localPosition = new Vector3(0, 1.5f, 0);
|
||||
|
||||
float tickDamage = damage / time;
|
||||
while(time <=0)
|
||||
|
||||
Debug.Log($"damage: {damage}");
|
||||
Debug.Log($"time: {time}");
|
||||
Debug.Log($"tickDamage: {tickDamage}");
|
||||
Debug.Log($"CurrentHP : {health.CurrentHP}");
|
||||
|
||||
try
|
||||
{
|
||||
health.ChangeHP(Mathf.FloorToInt(tickDamage)); //소수점 전부 버림
|
||||
if (health.CurrentHP <= 0) break;
|
||||
time--;
|
||||
await Task.Yield();
|
||||
while (time > 0)
|
||||
{
|
||||
Debug.Log($"진입");
|
||||
health.ChangeHP(health.CurrentHP - Mathf.FloorToInt(tickDamage)); //소수점 전부 버림
|
||||
if (health.CurrentHP <= 0) break;
|
||||
time--;
|
||||
Debug.Log($"중독 HP : {GameManager.Instance.Level.CurrentCharacter.GetComponent<Health>().CurrentHP}");
|
||||
await Task.Delay(1000, token);
|
||||
}
|
||||
}
|
||||
catch (System.OperationCanceledException)
|
||||
{
|
||||
Debug.Log("데미지 루프가 취소됨");
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 정상 종료되든, 취소되든(Exception) 이펙트는 확실히 제거
|
||||
if (fx_Visual != null) Destroy(fx_Visual);
|
||||
}
|
||||
Destroy(fx_Visual);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,9 +108,14 @@ public void OnSceneLoaded(Scene scene, LoadSceneMode mode)
|
||||
InputManager.Instance.OnAimToggleEvent += CurrentCharacterController.AimToggleInput;
|
||||
InputManager.Instance.OnLookEvent += CurrentCharacterController.LookInput;
|
||||
InputManager.Instance.OnDodgeEvent += CurrentCharacterController.DodgeInput;
|
||||
|
||||
//공격매핑
|
||||
//InputManager.Instance.OnNormalAttackEvent;
|
||||
//InputManager.Instance.OnHeavyAttackEvent;
|
||||
|
||||
//기타매핑
|
||||
InputManager.Instance.OnInteractionEvent += CurrentCharacterController.InteractInput;
|
||||
|
||||
//UI매핑
|
||||
InputManager.Instance.OnKeyDown_IKeyEvent += GameManager.Instance.InGameUI.InventoryToggle;
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
|
||||
public class InGameUIManager : BaseUIManager
|
||||
{
|
||||
public SplitWindowUI SplitWindowUI;
|
||||
public TooltipUI TooltipUI;
|
||||
public InteractionUI Interaction;
|
||||
public SplitWindowUI SplitWindow;
|
||||
public TooltipUI Tooltip;
|
||||
public Transform DragCanvas;
|
||||
public GameObject InventoryRoot;
|
||||
|
||||
@@ -17,7 +18,7 @@ public void VisibleCrossHair(bool isOn)
|
||||
|
||||
public SplitWindowUI GetSplitWindowUI()
|
||||
{
|
||||
return SplitWindowUI;
|
||||
return SplitWindow;
|
||||
}
|
||||
|
||||
public void InventoryToggle()
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
using UnityEditor.Experimental.GraphView;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using static Unity.Cinemachine.CinemachineSplineDolly;
|
||||
using static UnityEngine.Rendering.DebugUI;
|
||||
|
||||
@@ -75,6 +76,10 @@ public enum PlayerRotationMode {CameraCoupled, CameraDecoupled}
|
||||
public PlayerStat PlayerCharacterStat{ get; set; }
|
||||
private Renderer[] _renderers;
|
||||
|
||||
//상호작용
|
||||
public SphereCollider InteractionCollider;
|
||||
public List<IInteractable> InteractionTargets = new List<IInteractable>();
|
||||
|
||||
//무기
|
||||
//[SerializeField] private Weapon _weapon;
|
||||
|
||||
@@ -127,6 +132,9 @@ private void Update()
|
||||
|
||||
TickTimer();
|
||||
//PlayerDebug();
|
||||
|
||||
|
||||
Debug.Log($"InteractionTargetsCount : {InteractionTargets.Count}");
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
@@ -395,6 +403,13 @@ private void JumpAction()
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region
|
||||
private void PointSitAction()
|
||||
{
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 타미어
|
||||
private void TickTimer()
|
||||
{
|
||||
@@ -516,6 +531,15 @@ public void AimToggleInput(InputState inputState)
|
||||
}
|
||||
}
|
||||
|
||||
public void InteractInput()
|
||||
{
|
||||
if (InteractionTargets.Count > 0)
|
||||
{
|
||||
IInteractable target = InteractionTargets[0];
|
||||
target.InteractExec(this); // 실제 상호작용 실행
|
||||
}
|
||||
}
|
||||
|
||||
public void LookInput(Vector2 lookInput)
|
||||
{
|
||||
_lookInput = lookInput;
|
||||
@@ -562,4 +586,27 @@ public void SetCursorLockState(bool isLocked)
|
||||
Cursor.visible = !isLocked;
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void OnTriggerEnter(Collider other)
|
||||
{
|
||||
// 상호작용 객체인지 확인
|
||||
if (other.TryGetComponent<IInteractable>(out IInteractable interactable))
|
||||
{
|
||||
Debug.Log($"interactableName : {interactable}");
|
||||
|
||||
interactable.InteractOpen();
|
||||
InteractionTargets.Add(interactable);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnTriggerExit(Collider other)
|
||||
{
|
||||
// 상호작용 객체인지 확인
|
||||
if (other.TryGetComponent<IInteractable>(out IInteractable interactable))
|
||||
{
|
||||
interactable.InteractClose();
|
||||
InteractionTargets.Remove(interactable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
public class PlayerHealth : Health
|
||||
{
|
||||
[SerializeField] private PlayerStat _pstat;
|
||||
[SerializeField] PlayerStat _pstat;
|
||||
|
||||
public PlayerStat Pstat { get { return _pstat; } }
|
||||
|
||||
void Start()
|
||||
{
|
||||
|
||||
8
Assets/02_Scripts/UI/Interaction.meta
Normal file
8
Assets/02_Scripts/UI/Interaction.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 887b7a57494d12e408e866f712b84e7e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
31
Assets/02_Scripts/UI/Interaction/InteractionUI.cs
Normal file
31
Assets/02_Scripts/UI/Interaction/InteractionUI.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
public class InteractionUI : MonoBehaviour
|
||||
{
|
||||
public TextMeshProUGUI NameText; //대화창 이름
|
||||
public TextMeshProUGUI DialogText; //대화창 내용
|
||||
public GameObject DialogPopup; // 대화창
|
||||
|
||||
[SerializeField] private GameObject _sit_Interaction_Box;
|
||||
[SerializeField] private GameObject _pushHard_Interaction_Box;
|
||||
|
||||
public void UpdateSitBox(Transform sitTransform) //앉는 위치를 아이콘이 따라 다니도록
|
||||
{
|
||||
if (sitTransform == null) return;
|
||||
Vector3 pos = Camera.main.WorldToScreenPoint(sitTransform.position + sitTransform.up * 0.5f); //아이콘 위치
|
||||
}
|
||||
|
||||
public void OnOffSitBox(bool isOn) //앉기 아이콘 온오프용
|
||||
{
|
||||
if (_sit_Interaction_Box != null)
|
||||
_sit_Interaction_Box.gameObject.SetActive(isOn);
|
||||
}
|
||||
|
||||
public void UpdateSitBoxPos(Vector3 pos)
|
||||
{
|
||||
_sit_Interaction_Box.transform.position = pos;
|
||||
}
|
||||
}
|
||||
2
Assets/02_Scripts/UI/Interaction/InteractionUI.cs.meta
Normal file
2
Assets/02_Scripts/UI/Interaction/InteractionUI.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 401e7ae784ecbac46af9332f1347cd78
|
||||
@@ -76,7 +76,7 @@ public void OnEndDrag(PointerEventData eventData)
|
||||
{
|
||||
if (slot.currentItem != null && slot.currentItem.Data != null)
|
||||
{
|
||||
GameManager.Instance.InGameUI.TooltipUI.ShowTooltip(slot.currentItem, slot.GetComponent<RectTransform>());
|
||||
GameManager.Instance.InGameUI.Tooltip.ShowTooltip(slot.currentItem, slot.GetComponent<RectTransform>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,12 +151,12 @@ public void OnPointerEnter(PointerEventData eventData)
|
||||
if (eventData.dragging)
|
||||
{
|
||||
_highlightBox.gameObject.SetActive(false);
|
||||
GameManager.Instance.InGameUI.TooltipUI.HideTooltip();
|
||||
GameManager.Instance.InGameUI.Tooltip.HideTooltip();
|
||||
return;
|
||||
}
|
||||
|
||||
_highlightBox.gameObject.SetActive(true);
|
||||
GameManager.Instance.InGameUI.TooltipUI.ShowTooltip(currentItem, GetComponent<RectTransform>());
|
||||
GameManager.Instance.InGameUI.Tooltip.ShowTooltip(currentItem, GetComponent<RectTransform>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,19 +169,19 @@ public void OnPointerMove(PointerEventData eventData)
|
||||
if (eventData.dragging || !RectTransformUtility.RectangleContainsScreenPoint(_rectTransform, eventData.position, eventData.pressEventCamera))
|
||||
{
|
||||
_highlightBox.gameObject.SetActive(false);
|
||||
GameManager.Instance.InGameUI.TooltipUI.HideTooltip();
|
||||
GameManager.Instance.InGameUI.Tooltip.HideTooltip();
|
||||
return;
|
||||
}
|
||||
|
||||
_highlightBox.gameObject.SetActive(true);
|
||||
GameManager.Instance.InGameUI.TooltipUI.ShowTooltip(currentItem, GetComponent<RectTransform>());
|
||||
GameManager.Instance.InGameUI.Tooltip.ShowTooltip(currentItem, GetComponent<RectTransform>());
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPointerExit(PointerEventData eventData)
|
||||
{
|
||||
_highlightBox.gameObject.SetActive(false);
|
||||
GameManager.Instance.InGameUI.TooltipUI.HideTooltip();
|
||||
GameManager.Instance.InGameUI.Tooltip.HideTooltip();
|
||||
}
|
||||
|
||||
public void OnPointerClick(PointerEventData eventData)
|
||||
|
||||
Reference in New Issue
Block a user