Merge branch 'main' into DEG-143-세이브-강화-병합

This commit is contained in:
99jamin 2025-05-13 13:32:27 +09:00
commit 979d191ca8
55 changed files with 1392 additions and 208 deletions

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="c3b8a67e-61ad-4d5a-9de5-dce8e18c1710" name="변경" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="HighlightingSettingsPerFile">
<setting file="file://$APPLICATION_CONFIG_DIR$/resharper-host/DecompilerCache/decompiler/d6bbda9f0f5a4a7b944aefffbac6e8501fe00/57/cd48a3dd/CharacterController.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Assets/LIN/Scripts/PlayerStateExhaustion.cs" root0="FORCE_HIGHLIGHTING" />
<setting file="file://$PROJECT_DIR$/Assets/LIN/Scripts/UI/SwitchingPanelController.cs" root0="FORCE_HIGHLIGHTING" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"node.js.selected.package.tslint": "(autodetect)"
}
}]]></component>
<component name="RunManager">
<configuration name="유닛 테스트(배치 모드)" type="RunUnityExe" factoryName="Unity Executable">
<option name="EXE_PATH" value="C:\Program Files\Unity\Hub\Editor\2022.3.60f1\Editor\Unity.exe" />
<option name="PROGRAM_PARAMETERS" value="-runTests -batchmode -projectPath D:\LikeLion\TeamProject\TEAFridge\exhaustion -testResults Logs/results.xml -logFile Logs/Editor.log -testPlatform EditMode -debugCodeOptimization" />
<option name="WORKING_DIRECTORY" value="D:\LikeLion\TeamProject\TEAFridge\exhaustion" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<method v="2" />
</configuration>
<configuration name="Unity 시작" type="RunUnityExe" factoryName="Unity Executable">
<option name="EXE_PATH" value="C:\Program Files\Unity\Hub\Editor\2022.3.60f1\Editor\Unity.exe" />
<option name="PROGRAM_PARAMETERS" value="-projectPath D:\LikeLion\TeamProject\TEAFridge\exhaustion -debugCodeOptimization" />
<option name="WORKING_DIRECTORY" value="D:\LikeLion\TeamProject\TEAFridge\exhaustion" />
<option name="PASS_PARENT_ENVS" value="1" />
<option name="USE_EXTERNAL_CONSOLE" value="0" />
<method v="2" />
</configuration>
</component>
<component name="TaskManager">
<servers />
</component>
<component name="UnityProjectConfiguration" hasMinimizedUI="true" />
<component name="UnityUnitTestConfiguration" currentTestLauncher="Both" />
</project>

BIN
Assets/JAY/Animation/CustomAttack01.anim (Stored with Git LFS)

Binary file not shown.

BIN
Assets/JAY/Animation/CustomAttack02.anim (Stored with Git LFS)

Binary file not shown.

View File

@ -8,16 +8,6 @@ public class AnimatorEventRelay : MonoBehaviour
{
_playerController = GetComponentInParent<PlayerController>();
}
public void SetAttackComboTrue()
{
_playerController?.SetAttackComboTrue();
}
public void SetAttackComboFalse()
{
_playerController?.SetAttackComboFalse();
}
public void PlayAttackEffect()
{

View File

@ -2,72 +2,83 @@
public class PlayerActionAttack : IPlayerAction {
private static readonly int ComboStep = Animator.StringToHash("ComboStep");
private PlayerController player;
private int comboStep = 1;
private bool comboQueued = false;
private bool canReceiveCombo = false;
public int CurrentComboStep => comboStep;
private float comboTimer = 0f;
[SerializeField] private float comboDuration = 0.7f;
private int maxComboStep = 4;
public bool IsActive { get; private set; }
public int CurrentComboStep => comboStep;
public void StartAction(PlayerController player) {
this.player = player;
IsActive = true;
comboStep = 1;
comboQueued = false;
PlayComboAnimation(comboStep);
canReceiveCombo = true;
comboTimer = 0f;
player.SafeSetBool("Attack", true);
PlayComboAnimation(comboStep);
}
public void UpdateAction() {
if (Input.GetKeyDown(KeyCode.X) && canReceiveCombo) {
comboTimer += Time.deltaTime;
if (canReceiveCombo && Input.GetKeyDown(KeyCode.X)) {
comboQueued = true;
}
if (comboTimer >= comboDuration) {
ProceedComboOrEnd();
}
}
private void ProceedComboOrEnd() {
canReceiveCombo = false;
if (comboQueued && comboStep < maxComboStep) {
comboStep++;
comboQueued = false;
comboTimer = 0f;
canReceiveCombo = true;
PlayComboAnimation(comboStep);
} else {
EndAction();
}
}
public void EndAction() {
if (player == null) return;
player.WeaponController.AttackEnd();
player.SafeSetBool("Attack", false);
IsActive = false;
player.OnActionEnded(this); // player 에서도 action 초기화
player.OnActionEnded(this);
player = null;
}
public void EnableCombo() {
canReceiveCombo = true;
}
private void PlayComboAnimation(int step) {
if (player?.PlayerAnimator == null) return;
public void DisableCombo() {
canReceiveCombo = false;
player.PlayerAnimator.SetInteger(ComboStep, step);
if (comboQueued && comboStep < 4) {
comboStep++;
PlayComboAnimation(comboStep);
comboQueued = false;
} else {
EndAction(); // 행동 종료
}
}
private void PlayComboAnimation(int step)
{
if (player.PlayerAnimator == null) return;
// 안전하게 파라미터 체크
foreach (var param in player.PlayerAnimator.parameters)
{
if (param.nameHash == ComboStep && param.type == AnimatorControllerParameterType.Int)
{
player.PlayerAnimator.SetInteger(ComboStep, step);
break;
}
}
// 무기에 콤보 단계 전달
var weapon = player.GetComponentInChildren<WeaponController>();
if (weapon != null)
{
weapon.SetComboStep(step);
weapon?.SetComboStep(step);
player.WeaponController.AttackStart();
}
public void OnComboInput() {
if (canReceiveCombo) {
comboQueued = true;
}
}
}
}

View File

@ -24,10 +24,8 @@ public class PlayerController : CharacterBase, IObserver<GameObject>
private bool _isBattle;
private GameObject weapon;
private WeaponController _weaponController;
private float attackUpgradeLevel;
private float moveSpeedUpgradeLevel;
private float dashCooldownUpgradeLevel;
public WeaponController WeaponController => _weaponController;
private IPlayerState _currentStateClass { get; set; }
private IPlayerAction _currentAction;
public IPlayerAction CurrentAction => _currentAction;
@ -51,13 +49,6 @@ public class PlayerController : CharacterBase, IObserver<GameObject>
public CharacterController CharacterController => _characterController;
public bool IsBattle => _isBattle;
public Transform DashEffectAnchor => dashEffectAnchor;
// 대시 쿨타임 관련
[SerializeField] private float dashCooldownDuration = 1.5f;
private float dashCooldownTimer = 0f;
public bool IsDashOnCooldown => dashCooldownTimer > 0f;
public float DashCooldownRatio => dashCooldownTimer / dashCooldownDuration;
private void Awake()
{
@ -81,15 +72,6 @@ public class PlayerController : CharacterBase, IObserver<GameObject>
hitEffectController = GetComponentInChildren<PlayerHitEffectController>();
PlayerInit();
//강화 적용
attackUpgradeLevel = 1 + (float)UpgradeManager.Instance.upgradeStat.CurrentUpgradeLevel(StatType.AttackPower)/2;
moveSpeedUpgradeLevel = 1 + (float)UpgradeManager.Instance.upgradeStat.CurrentUpgradeLevel(StatType.MoveSpeed)/2;
dashCooldownUpgradeLevel = (float)UpgradeManager.Instance.upgradeStat.CurrentUpgradeLevel(StatType.DashCoolDown)/4;
attackPower *= attackUpgradeLevel;
moveSpeed *= moveSpeedUpgradeLevel;
dashCooldownDuration -= dashCooldownUpgradeLevel;
}
private void Update()
@ -99,10 +81,6 @@ public class PlayerController : CharacterBase, IObserver<GameObject>
_playerStates[CurrentState].Update();
}
// 대시 쿨타임 진행
if (dashCooldownTimer > 0f)
dashCooldownTimer -= Time.deltaTime;
// Hit 상태거나 게임 끝났을 땐 땐 입력 무시
if (CurrentState == PlayerState.Hit || CurrentState == PlayerState.Dead || CurrentState == PlayerState.Win)
return;
@ -253,13 +231,6 @@ public class PlayerController : CharacterBase, IObserver<GameObject>
{
if (!_isBattle) return;
// 쿨타임 중이면 무시
if (IsDashOnCooldown)
{
Debug.Log("대시 쿨타임 중");
return;
}
// 만약 공격 중이면 강제로 공격 종료
if (_currentAction == _attackAction && _attackAction.IsActive)
{
@ -273,9 +244,6 @@ public class PlayerController : CharacterBase, IObserver<GameObject>
_currentAction = _actionDash;
_actionDash.StartAction(this);
// 쿨타임 시작
dashCooldownTimer = dashCooldownDuration;
}
public void OnActionEnded(IPlayerAction action)
@ -324,27 +292,7 @@ public class PlayerController : CharacterBase, IObserver<GameObject>
// 무기도 전투모드에만
weapon.SetActive(_isBattle);
}
// Animation Event에서 호출될 메서드
public void SetAttackComboTrue()
{
if (_weaponController.IsAttacking) return; // 이미 공격 중이면 실행 안함
if (_currentAction == _attackAction) {
_attackAction.EnableCombo();
_weaponController.AttackStart();
}
}
public void SetAttackComboFalse()
{
if (_currentAction == _attackAction) {
// 이벤트 중복 호출? 공격 종료 시 SetAttackComboFalse가 아니라 ~True로 끝나서 오류 발생. (공격 안하는 상태여도 공격으로 판정됨)
_attackAction.DisableCombo();
_weaponController.AttackEnd(); // IsAttacking = false로 변경
}
}
public void PlayAttackEffect()
{
if (_attackAction == null) return;
@ -383,6 +331,10 @@ public class PlayerController : CharacterBase, IObserver<GameObject>
GameManager.Instance.PlayPlayerAttackSound();
StartAttackAction();
}
else if (_currentAction is PlayerActionAttack attackAction)
{
attackAction.OnComboInput();
}
}
#endregion

BIN
Assets/JYY/Prefabs/Alien Big Blink.prefab (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
Assets/JYY/Scenes/MonsterTest.unity (Stored with Git LFS)

Binary file not shown.

View File

@ -2,9 +2,10 @@ using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using Random = UnityEngine.Random;
public class PlayerStats : MonoBehaviour, ISaveable
public class PlayerStats : MonoBehaviour
{
public class StatsChangeData // 변경된 스탯 데이터
{
@ -29,7 +30,7 @@ public class PlayerStats : MonoBehaviour, ISaveable
public event Action OnDayEnded;
public event Action Exhaustion; // 탈진
public event Action Overslept; // 결근(늦잠)
public event Action Overslept; // 늦잠
public event Action ZeroReputation; // 평판 0 이벤트
public event Action<StatsChangeData> OnStatsChanged; // 스탯 변경 이벤트
public event Action OnWorked; // 퇴근 이벤트 (출근 이후 집에 돌아올 시간에 발생)
@ -37,6 +38,18 @@ public class PlayerStats : MonoBehaviour, ISaveable
private float previousAddHealth = 0f;
public static PlayerStats Instance;
// 결근 이벤트 관련 변수
private bool _hasWorkedToday = false;
private bool _hasCheckedAbsenceToday = false; // 결근 체크, 하루에 결근 여러 번 체크 안하기 위함
public event Action OnAbsent; // 결근
// 말풍선
private GameObject messagePanelInstance;
private SpeechBubbleFollower speechBubbleFollower;
private bool isActiveBubble;
private bool hasShownBubbleToday; // 하루에 말풍선 하나만 표시하기
private void Awake()
{
if (Instance == null)
@ -59,7 +72,88 @@ public class PlayerStats : MonoBehaviour, ISaveable
{
_valueByAction = new ValueByAction();
_valueByAction.Initialize(); // 값 초기화
LoadMessagePanel();
CheckBubble();
SceneManager.sceneLoaded += OnSceneLoaded; // 씬 전환 이벤트
}
#region (Bubble)
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
// 새 씬에서 메시지 패널 다시 로드
LoadMessagePanel();
CheckBubble();
}
// OnDestroy에서 이벤트 구독 해제
private void OnDestroy()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
private void LoadMessagePanel()
{
if (messagePanelInstance != null) // 기존 패널 파괴
{
Destroy(messagePanelInstance);
messagePanelInstance = null;
}
GameObject messagePanelPrefab = Resources.Load<GameObject>("Prefabs/MessagePanel");
if (messagePanelPrefab != null)
{
Canvas canvas = FindObjectOfType<Canvas>();
messagePanelInstance = Instantiate(messagePanelPrefab, canvas.transform);
speechBubbleFollower = messagePanelInstance.GetComponent<SpeechBubbleFollower>();
speechBubbleFollower.SetPlayerTransform();
if (speechBubbleFollower != null)
{
isActiveBubble = false;
hasShownBubbleToday = false;
speechBubbleFollower.HideMessage();
}
}
}
private void CheckBubble()
{
if (isActiveBubble)
{
isActiveBubble = false;
HideBubble();
}
if (TimeStat >= 8.0f && TimeStat < 9.0f && !isActiveBubble && !hasShownBubbleToday)
{
hasShownBubbleToday = true;
isActiveBubble = true;
ShowBubble();
}
}
public void ShowBubble()
{
if(isActiveBubble)
speechBubbleFollower.ShowMessage();
}
public void HideBubble()
{
speechBubbleFollower.HideMessage();
}
public void ShowAndHideBubble(string text)
{
speechBubbleFollower.ShowAndHide(text);
}
#endregion
// 현재 체력으로 해당 행동이 가능한 지 확인
public bool CanPerformByHealth(ActionType actionType)
@ -69,6 +163,23 @@ public class PlayerStats : MonoBehaviour, ISaveable
return (HealthStat >= (effect.healthChange * -1));
}
// 결근 체크
public void CheckAbsent()
{
if (_hasWorkedToday || _hasCheckedAbsenceToday)
return;
// 9시가 지났는데 출근하지 않은 경우
if (TimeStat >= 9.0f && !_hasWorkedToday)
{
_hasCheckedAbsenceToday = true; // 결근 체크 완료 표시
OnAbsent?.Invoke();
PerformAction(ActionType.Absence); // 평판 -3
Debug.Log("결근 처리: 평판 감소" + ReputationStat);
}
}
// 행동 처리 메서드
public void PerformAction(ActionType actionType)
{
@ -86,6 +197,7 @@ public class PlayerStats : MonoBehaviour, ISaveable
// 스탯 - 시간이 변경된 이후 퇴근 이벤트 발생
if (actionType == ActionType.Work)
{
_hasWorkedToday = true;
OnWorked?.Invoke();
}
}
@ -156,6 +268,11 @@ public class PlayerStats : MonoBehaviour, ISaveable
// 하루가 실제로 종료된 경우에만 이벤트 발생
if (isDayEnded)
{
// 결근 관련 변수 초기화
_hasWorkedToday = false;
_hasCheckedAbsenceToday = false;
hasShownBubbleToday = false;
OnDayEnded?.Invoke();
}
}
@ -173,16 +290,20 @@ public class PlayerStats : MonoBehaviour, ISaveable
return ( wakeUpTime + 24f ) - timeStat; // 다음 날 오전 8시까지 남은 시간
}
}
#region Modify Stats
// 행동에 따른 내부 스탯 변경 메서드
public void ModifyTime(float time, ActionType actionType)
{
TimeStat += time;
if (TimeStat >= _gameConstants.maxTime)
{
EndDay(time, actionType);
}
CheckBubble();
}
public void ModifyHealth(float health)
@ -211,11 +332,17 @@ public class PlayerStats : MonoBehaviour, ISaveable
public void ModifyReputation(float reputation)
{
// float 연산 시 계산 오차가 발생할 수도 있기에 소수점 두 번째에서 반올림하도록 처리
ReputationStat = Mathf.Round((ReputationStat + reputation) * 100f) / 100f;
if(ReputationStat > 0)
{
ReputationStat = Mathf.Round((ReputationStat + reputation) * 100f) / 100f;
}
else
{
ReputationStat = 0f;
}
if (ReputationStat <= 0)
{
Debug.Log("당신의 평판은 0입니다..;");
ZeroReputation?.Invoke();
ReputationStat = 0.0f;
}
@ -225,27 +352,6 @@ public class PlayerStats : MonoBehaviour, ISaveable
ReputationStat = _gameConstants.maxReputation;
}
}
public void ApplySaveData(Save save)
{
if (save?.homeSave != null)
{
TimeStat = save.homeSave.time;
HealthStat = save.homeSave.health;
ReputationStat = save.homeSave.reputation;
}
}
public Save ExtractSaveData()
{
return new Save
{
homeSave = new HomeSave
{
time = this.TimeStat,
health = this.HealthStat,
reputation = this.ReputationStat,
}
};
}
#endregion
}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fc6d3130a52463e41839b27861b56c13
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/KSH/ReHousing.unity (Stored with Git LFS)

Binary file not shown.

View File

@ -0,0 +1,156 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-2852132483883391422
MonoBehaviour:
m_ObjectHideFlags: 3
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 97c23e3b12dc18c42a140437e53d3951, type: 3}
m_Name: Tonemapping
m_EditorClassIdentifier:
active: 1
mode:
m_OverrideState: 1
m_Value: 1
neutralHDRRangeReductionMode:
m_OverrideState: 0
m_Value: 2
acesPreset:
m_OverrideState: 0
m_Value: 3
hueShiftAmount:
m_OverrideState: 0
m_Value: 0
detectPaperWhite:
m_OverrideState: 0
m_Value: 0
paperWhite:
m_OverrideState: 0
m_Value: 300
detectBrightnessLimits:
m_OverrideState: 0
m_Value: 1
minNits:
m_OverrideState: 0
m_Value: 0.005
maxNits:
m_OverrideState: 0
m_Value: 1000
--- !u!114 &-2712325431816409236
MonoBehaviour:
m_ObjectHideFlags: 3
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0b2db86121404754db890f4c8dfe81b2, type: 3}
m_Name: Bloom
m_EditorClassIdentifier:
active: 1
skipIterations:
m_OverrideState: 0
m_Value: 1
threshold:
m_OverrideState: 1
m_Value: 1
intensity:
m_OverrideState: 1
m_Value: 4
scatter:
m_OverrideState: 1
m_Value: 0.7
clamp:
m_OverrideState: 1
m_Value: 65472
tint:
m_OverrideState: 0
m_Value: {r: 1, g: 1, b: 1, a: 1}
highQualityFiltering:
m_OverrideState: 0
m_Value: 0
downscale:
m_OverrideState: 0
m_Value: 0
maxIterations:
m_OverrideState: 0
m_Value: 6
dirtTexture:
m_OverrideState: 0
m_Value: {fileID: 0}
dimension: 1
dirtIntensity:
m_OverrideState: 0
m_Value: 0
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d7fd9488000d3734a9e00ee676215985, type: 3}
m_Name: Global Volume Profile
m_EditorClassIdentifier:
components:
- {fileID: 8137804423515573767}
- {fileID: -2712325431816409236}
- {fileID: 8337002668884885685}
- {fileID: -2852132483883391422}
--- !u!114 &8137804423515573767
MonoBehaviour:
m_ObjectHideFlags: 3
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 66f335fb1ffd8684294ad653bf1c7564, type: 3}
m_Name: ColorAdjustments
m_EditorClassIdentifier:
active: 1
postExposure:
m_OverrideState: 1
m_Value: 0.5
contrast:
m_OverrideState: 0
m_Value: 0
colorFilter:
m_OverrideState: 0
m_Value: {r: 1, g: 1, b: 1, a: 0}
hueShift:
m_OverrideState: 0
m_Value: 0
saturation:
m_OverrideState: 1
m_Value: 25
--- !u!114 &8337002668884885685
MonoBehaviour:
m_ObjectHideFlags: 3
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 70afe9e12c7a7ed47911bb608a23a8ff, type: 3}
m_Name: SplitToning
m_EditorClassIdentifier:
active: 1
shadows:
m_OverrideState: 0
m_Value: {r: 1, g: 1, b: 1, a: 0}
highlights:
m_OverrideState: 1
m_Value: {r: 1, g: 0.81578505, b: 0.6179246, a: 0}
balance:
m_OverrideState: 0
m_Value: 0

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 05a231865f1a03449ab9f5a6c76e0989
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,120 @@
using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class SpeechBubbleFollower : MonoBehaviour
{
[SerializeField] private Transform playerTransform;
[SerializeField] private TMP_Text bubbleText;
private Vector3 offset = new Vector3(200f, 250f, 0);
private Camera mainCamera;
private RectTransform rectTransform;
private CanvasGroup canvasGroup;
private float minDistance = 3f;
private float maxDistance = 8f;
private float minOffsetScale = 0.7f;
private Coroutine hideCoroutine; // 자동 숨김용 코루틴
// 랜덤 메시지
private string[] workReminderMessages = new string[]
{
"8시.. 출근하자.",
"출근...해야 하나.",
"회사가 기다린다."
};
private void Awake()
{
rectTransform = GetComponent<RectTransform>();
canvasGroup = GetComponent<CanvasGroup>();
if (canvasGroup == null)
canvasGroup = gameObject.AddComponent<CanvasGroup>();
gameObject.SetActive(false);
}
private void Start()
{
mainCamera = Camera.main;
SetPlayerTransform();
}
public void SetPlayerTransform()
{
if (playerTransform == null)
{
playerTransform = GameObject.FindGameObjectWithTag("Player").transform;
}
}
private void LateUpdate()
{
if (!gameObject.activeInHierarchy || playerTransform == null)
return;
// Z축 거리 계산
float zDistance = Mathf.Abs(mainCamera.transform.position.z - playerTransform.position.z);
// 거리에 따른 오프셋 비율 계산 (멀어질수록 작아짐)
float normalizedDistance = Mathf.Clamp01((zDistance - minDistance) / (maxDistance - minDistance));
float offsetScale = Mathf.Lerp(1f, minOffsetScale, normalizedDistance);
// 실제 적용할 오프셋 계산
Vector3 scaledOffset = offset * offsetScale;
// 플레이어 위치를 스크린 좌표로 변환
Vector3 screenPosition = mainCamera.WorldToScreenPoint(playerTransform.position);
screenPosition.z = 0;
// 위치 적용
transform.position = screenPosition + scaledOffset;
}
public void ShowMessage() // 랜덤 텍스트 표시
{
string message = workReminderMessages[Random.Range(0, workReminderMessages.Length)];
if (bubbleText != null)
bubbleText.text = message;
gameObject.SetActive(true);
canvasGroup.alpha = 1f;
}
public void HideMessage()
{
gameObject.SetActive(false);
}
public void ShowAndHide(string text)
{
// 텍스트 설정
if (bubbleText != null)
bubbleText.text = text;
// 말풍선 활성화
gameObject.SetActive(true);
canvasGroup.alpha = 1f;
// 이전에 실행 중인 코루틴이 있다면 중지
if (hideCoroutine != null)
StopCoroutine(hideCoroutine);
// 3초 후 자동 숨김 코루틴 시작
hideCoroutine = StartCoroutine(HideAfterDelay(3f));
}
// 일정 시간 후 말풍선을 숨기는 코루틴
private IEnumerator HideAfterDelay(float delay)
{
yield return new WaitForSeconds(delay);
HideMessage();
hideCoroutine = null;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 91cfaa5ec19c50b41ac2d6c542b51cd1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/LIN/Prefabs/SwitchingImage.prefab (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5f886fa5087dfb04780f508410f72e46
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

BIN
Assets/LIN/ReHousing Copy.unity (Stored with Git LFS)

Binary file not shown.

View File

@ -10,8 +10,8 @@ public class InteractionController : MonoBehaviour
{
[SerializeField] LayerMask interactionLayerMask;
[Header("UI 연동")] [SerializeField]
HousingCanvasController housingCanvasController;
[Header("UI 연동")]
[SerializeField] private HousingCanvasController housingCanvasController;
[SerializeField] private InteractionAnimationPanelController interactionAnimationPanelController;
@ -23,6 +23,7 @@ public class InteractionController : MonoBehaviour
// 상호작용 가능한 사물 범위에 들어올 때
private void OnTriggerEnter(Collider other)
{
PlayerStats.Instance.HideBubble();
if (other.gameObject.layer == LayerMask.NameToLayer("NPC"))
{
housingCanvasController.ShowNpcInteractionButton(() =>
@ -30,7 +31,7 @@ public class InteractionController : MonoBehaviour
GameManager.Instance.StartNPCDialogue(GamePhase.Gameplay);
});
}
if (interactionLayerMask == (interactionLayerMask | (1 << other.gameObject.layer)))
{
ActionType interactionType = other.gameObject.GetComponent<InteractionProp>().RoutineEnter();
@ -48,39 +49,48 @@ public class InteractionController : MonoBehaviour
if (interactionLayerMask == (interactionLayerMask | (1 << other.gameObject.layer)))
{
PlayerStats.Instance.ShowBubble();
housingCanvasController.HideInteractionButton();
housingCanvasController.interactionTextsController.InitInteractionTexts();
}
}
// ActionType 별로 화면에 상호작용 내용 표시, 상호작용 버튼에 이벤트 작성
private void PopActionOnScreen(ActionType interactionType)
{
HousingConstants.interactions.TryGetValue(interactionType, out var interactionTexts);
housingCanvasController.ShowInteractionButton(interactionTexts.ActionText, interactionTexts.DescriptionText,
() =>
housingCanvasController.ShowInteractionButton(interactionTexts.ActionText,interactionTexts.DescriptionText,()=>
{
if (PlayerStats.Instance.CanPerformByHealth(interactionType))
{
if (PlayerStats.Instance.CanPerformByHealth(interactionType))
if (interactionType == ActionType.Work)
{
PlayerStats.Instance.PerformAction(interactionType);
if (interactionType == ActionType.Dungeon)
if (!PlayerStats.Instance.CanWork()) // 출근 가능한 시간이 아닐 경우
{
GameManager.Instance.ChangeToGameScene();
}
else
{
GameManager.Instance.PlayInteractionSound(interactionType);
interactionAnimationPanelController.ShowAnimationPanel(interactionType,
interactionTexts.AnimationText);
PlayerStats.Instance.ShowAndHideBubble("출근 시간이 아냐");
return;
}
}
if (interactionType == ActionType.Dungeon)
{
GameManager.Instance.ChangeToGameScene();
}
else
{
housingCanvasController.interactionTextsController.ActiveTexts(interactionTexts.LackOfHealth);
GameManager.Instance.PlayInteractionSound(interactionType);
interactionAnimationPanelController.ShowAnimationPanel(interactionType,interactionTexts.AnimationText);
}
});
PlayerStats.Instance.PerformAction(interactionType);
}
else
{
PlayerStats.Instance.ShowAndHideBubble("체력이 없어...");
housingCanvasController.interactionTextsController.ActiveTexts(interactionTexts.LackOfHealth);
}
});
}
public Action SuddenEventHappen()

View File

@ -0,0 +1,25 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerStateEx : IPlayerState
{
private PlayerController _playerController;
public void Enter(PlayerController playerController)
{
// 파라미터가 존재하는지 확인 후 처리
_playerController.SafeSetBool("Dizzy", true);
}
public void Update()
{
}
public void Exit()
{
// 파라미터가 존재하는지 확인 후 처리
_playerController.SafeSetBool("Dizzy", false);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: de272c8986ac39344a9242a82a8d7cc4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -15,6 +15,10 @@ public class HousingCanvasController : MonoBehaviour
[SerializeField] private GameObject suddenPanel;
[SerializeField] private TMP_Text suddenText;
[SerializeField] private GameObject[] suddenEventImages;
[Header("로딩(스위칭) 패널")]
[SerializeField] private GameObject switchingPanel;
private SwitchingPanelController switchingPanelController;
private Coroutine _autoHideCoroutine;
@ -27,6 +31,19 @@ public class HousingCanvasController : MonoBehaviour
interactionButton.SetActive(false);
suddenPanel.SetActive(false);
}
/// <summary>
/// 씬전환 로딩 패널 테스트용 코드.던전에서도 씬전환 할 때 해당 코드 사용하시면 됩니다.
/// </summary>
private void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
var _switchingPanel = Instantiate(switchingPanel,this.transform);
switchingPanelController = _switchingPanel.GetComponent<SwitchingPanelController>();
switchingPanelController.FadeAndSceneLoad("ReDungeon");
}
}
#region NPC
@ -75,7 +92,6 @@ public class HousingCanvasController : MonoBehaviour
#region
public void ShowSuddenEventPanel(string actText, Action onSuddenButtonPressed)
{
Debug.Log("call evenet panel show");
suddenPanel.SetActive(true);
suddenText.text = actText;
OnSuddenButtonPressed += onSuddenButtonPressed;

View File

@ -16,6 +16,8 @@ public static class HousingConstants
public static int AFTER_WORK_DENOMINATOR = 2;
//돌발 이벤트 보여줄 시간
public static float SUDDENEVENT_IAMGE_SHOW_TIME = 4.0f;
//전환효과(Switching) 패널 애니메이션 시간
public static float SWITCH_PANEL_AINIM_DURATION = 2.0f;
#region

View File

@ -25,6 +25,8 @@ public class InteractionAnimationPanelController : MonoBehaviour
public void ShowAnimationPanel(ActionType actionType, string animationText)
{
PlayerStats.Instance.HideBubble();
// 1) 패널 활성화
panel.SetActive(true);
// 2) 기존 코루틴 정리
@ -33,6 +35,7 @@ public class InteractionAnimationPanelController : MonoBehaviour
// 3) 텍스트 및 애니메이션 세팅
doingText.text = animationText;
switch (actionType)
{
case ActionType.Sleep:
@ -107,6 +110,10 @@ public class InteractionAnimationPanelController : MonoBehaviour
StopCoroutine(_autoHideCoroutine);
_autoHideCoroutine = null;
}
// 패널 닫히고 결근 체크, 상호작용 패널과 결근 엔딩 채팅창이 겹치지 않기 위함
PlayerStats.Instance.CheckAbsent();
PlayerStats.Instance.ShowBubble();
}
public void TutorialSleepAnimation()

View File

@ -0,0 +1,60 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
using TMPro;
using UnityEngine.SceneManagement;
public class SwitchingPanelController : MonoBehaviour
{
[SerializeField] private GameObject Loading_UI;
[SerializeField] TMP_Text Loading_text;
private CanvasGroup canvasGroup;
private void Awake()
{
canvasGroup = this.GetComponent<CanvasGroup>();
canvasGroup.alpha = 0;
}
IEnumerator LoadScene(string sceneName){
Loading_UI.SetActive(true);
AsyncOperation async = SceneManager.LoadSceneAsync(sceneName);
async.allowSceneActivation = false; //퍼센트 딜레이용
float past_time = 0;
float percentage = 0;
while(!(async.isDone)){
yield return null;
past_time += Time.deltaTime;
if(percentage >= 90){
percentage = Mathf.Lerp(percentage, 100, past_time);
if(percentage == 100){
async.allowSceneActivation = true; //씬 전환 준비 완료
}
}
else{
percentage = Mathf.Lerp(percentage, async.progress * 100f, past_time);
if(percentage >= 90) past_time = 0;
}
Loading_text.text = percentage.ToString("0") + "%"; //로딩 퍼센트 표기
}
}
public void FadeAndSceneLoad(string sceneName)
{
if (canvasGroup == null) return;
canvasGroup.DOFade(1.0f, HousingConstants.SWITCH_PANEL_AINIM_DURATION).OnComplete(() =>
{
StartCoroutine(LoadScene(sceneName));
});
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b102a2215342ff14ea8214afcdf02dfe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/LYM/Ani/Housework.anim (Stored with Git LFS)

Binary file not shown.

File diff suppressed because one or more lines are too long

BIN
Assets/LYM/Materials/New Material.mat (Stored with Git LFS)

Binary file not shown.

BIN
Assets/LYM/Materials/concrete_tiles_02_diff_4k.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,114 @@
fileFormatVersion: 2
guid: 411260254e8ccef40a8017e896305585
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/LYM/Materials/concrete_tiles_02_disp_4k.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,114 @@
fileFormatVersion: 2
guid: ed31620bbac240f4aa7289202e0cc33c
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,114 @@
fileFormatVersion: 2
guid: db658755b48c0784382a680e38c34624
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 1
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,114 @@
fileFormatVersion: 2
guid: 4d835634a149dce429f968a5a6944a88
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 0
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

BIN
Assets/Prefabs/ReDungeon/Canvas.prefab (Stored with Git LFS)

Binary file not shown.

BIN
Assets/Prefabs/ReHousing/Plane.prefab (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 1fa6c1bbf9304354d96ab639c0461430
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -146,6 +146,55 @@
"text": "... GameManager.Instance.ShowCredit(GamePhase.End);",
"nextId": "",
"phase": "end"
},
{
"id": "fairy_zero_1",
"name": "냉장고 요정",
"text": "...",
"nextId": "player_zero_1",
"phase": "zero"
},
{
"id": "player_zero_1",
"name": "주인공",
"text": "...",
"nextId": "fairy_zero_2",
"phase": "zero"
},
{
"id": "fairy_zero_2",
"name": "냉장고 요정",
"text": "평판이... 0?",
"nextId": "player_zero_2",
"phase": "zero"
},
{
"id": "player_zero_2",
"name": "주인공",
"text": "...! (회사에서 연락이 온다.)",
"nextId": "fairy_zero_3",
"phase": "zero"
},
{
"id": "fairy_zero_3",
"name": "회사",
"text": "당신은 해고되었습니다.",
"nextId": "player_zero_3",
"phase": "zero"
},
{
"id": "player_zero_3",
"name": "주인공",
"text": "내가... 해고? 내가?",
"nextId": "fairy_zero_4",
"phase": "zero"
},
{
"id": "fairy_zero_4",
"name": " ",
"text": "그 날 서울시 어느 동네에서, 한 34세의 남성의 절규 소리가 울려퍼졌다.",
"nextId": "",
"phase": "zero"
}
]
}

BIN
Assets/Resources/Prefabs/MessagePanel.prefab (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 45ae814acb957c54785f24aefe6843e8
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -28,7 +28,7 @@ public class VerticalAoeController : AoeControllerBase
protected override void HitCheck()
{
// 박스 판정 (사각형 직선)
Vector3 halfExtents = new Vector3(_data.radius, 1f, _data.radius * 2f);
Vector3 halfExtents = new Vector3(_data.radius, 1f, _data.radius * 2f) * 0.5f;
Collider[] hits = Physics.OverlapBox(transform.position, halfExtents, transform.rotation, _data.targetLayer);
foreach (var hit in hits)
@ -47,7 +47,7 @@ public class VerticalAoeController : AoeControllerBase
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.color = Color.yellow;
Vector3 center = transform.position;
Vector3 size = new Vector3(_data.radius, 1f, _data.radius * 2f);
Gizmos.matrix = Matrix4x4.TRS(center, transform.rotation, Vector3.one);

View File

@ -26,6 +26,9 @@ public class BulletBase : MonoBehaviour
// 내부용
private Vector3 _direction = Vector3.forward;
private float _timer;
private Vector3 _prevPosition;
[SerializeField] private LayerMask _targetLayer;
public virtual void Initialize(BulletData bulletData)
{
@ -40,31 +43,41 @@ public class BulletBase : MonoBehaviour
transform.rotation = Quaternion.LookRotation(_direction);
_timer = 0f;
_prevPosition = transform.position;
}
private void Update()
{
// 1) 이동
transform.position += _direction * (_speed * Time.deltaTime);
float moveDist = _speed * Time.deltaTime;
// 2) 수명 카운트
// 1) Raycast 충돌 검사
if (Physics.Raycast(_prevPosition, _direction, out RaycastHit hit, moveDist, _targetLayer))
{
// 닿은 지점으로 이동
transform.position = hit.point;
OnBulletHit(hit);
return;
}
// 2) 실제 이동
transform.position += _direction * moveDist;
_prevPosition = transform.position;
// 3) 수명 검사
_timer += Time.deltaTime;
if (_timer >= _lifeTime)
{
DestroyBullet();
}
}
private void OnTriggerEnter(Collider other)
private void OnBulletHit(RaycastHit hit)
{
// TODO: 주인공 캐릭터를 찾는 로직 추가 필요
// 주인공 스크립트를 찾아 처리할 것.
var character = other.GetComponent<CharacterBase>();
if (character != null)
PlayerController playerController = hit.transform.GetComponent<PlayerController>();
Debug.Log(hit.transform.name);
if (playerController != null)
{
character.TakeDamage(_damage);
DestroyBullet();
playerController.TakeDamage(_damage);
}
DestroyBullet();
}
protected virtual void DestroyBullet()

View File

@ -5,8 +5,6 @@ using Random = UnityEngine.Random;
public class CasterDemonController : EnemyController
{
// Animation
public static readonly int Cast = Animator.StringToHash("Cast");
public static readonly int Flee = Animator.StringToHash("Flee");

View File

@ -35,7 +35,8 @@ public enum GamePhase // 단계별로 출력되는 대화가 달라짐
{
Intro, // 인트로 설명문
Gameplay, // 게임 진행 팁? 등
End // 엔딩 대화
End, // 엔딩 대화
ZeroEnd
}
public class ChatWindowController : MonoBehaviour, IPointerClickHandler
@ -90,6 +91,7 @@ public class ChatWindowController : MonoBehaviour, IPointerClickHandler
if (_inputQueue.Count > 0)
{
ShowNextDialogue();
PlayerStats.Instance.HideBubble();
}
}
@ -111,6 +113,8 @@ public class ChatWindowController : MonoBehaviour, IPointerClickHandler
StopCoroutine(_clickCoroutine);
_clickCoroutine = null;
}
PlayerStats.Instance.ShowBubble();
}
#endregion

View File

@ -86,6 +86,10 @@ public class FairyDialogueManager
else if (phase == GamePhase.End)
{
StartPhaseDialogue("end");
}
else if (phase == GamePhase.ZeroEnd)
{
StartPhaseDialogue("zero");
}
}

View File

@ -27,7 +27,11 @@ public partial class GameManager : Singleton<GameManager>, ISaveable
{
// 오디오 초기화
InitializeAudio();
PlayerStats.Instance.OnDayEnded += AdvanceDay;
// 이벤트 할당
PlayerStats.Instance.OnDayEnded += AdvanceDay; // 날짜 변경
PlayerStats.Instance.ZeroReputation += ZeroReputationEnd; // 평판 0 엔딩
//패널 매니저 생성
panelManager = Instantiate(Resources.Load<GameObject>("Prefabs/PanelManager")).GetComponent<PanelManager>();
}

View File

@ -16,9 +16,14 @@ public partial class GameManager
public void ClearStage()
{
Debug.Log($"스테이지 레벨 {stageLevel}을 클리어 하셨습니다!");
stageLevel++;
}
private void ZeroReputationEnd()
{
// npc와의 대화 출력, Phase = zero
StartNPCDialogue(GamePhase.ZeroEnd);
}
// 엔딩 관련 메서드. 7일차에 실행
private void TriggerTimeEnding()
@ -27,10 +32,10 @@ public partial class GameManager
StartNPCDialogue(GamePhase.End);
// 플레이어 상태에 따라 엔딩 판별
EndingType endingType = DetermineEnding();
// EndingType endingType = DetermineEnding();
// 엔딩 타입에 따라 다른 씬이나 UI 표시
switch (endingType)
/*switch (endingType)
{
case EndingType.Normal:
Debug.Log("던전 공략 성공");
@ -44,7 +49,7 @@ public partial class GameManager
Debug.Log("던전 공략 성공과 훌륭한 평판 작");
break;
}
}*/
}
// 던전 스테이지와 평판 수치로 엔딩 판별

View File

@ -13,6 +13,9 @@ MonoBehaviour:
m_Name: Bloom
m_EditorClassIdentifier:
active: 1
skipIterations:
m_OverrideState: 0
m_Value: 1
threshold:
m_OverrideState: 1
m_Value: 0.94
@ -31,9 +34,12 @@ MonoBehaviour:
highQualityFiltering:
m_OverrideState: 0
m_Value: 0
skipIterations:
downscale:
m_OverrideState: 0
m_Value: 1
m_Value: 0
maxIterations:
m_OverrideState: 0
m_Value: 6
dirtTexture:
m_OverrideState: 0
m_Value: {fileID: 0}
@ -102,6 +108,30 @@ MonoBehaviour:
mode:
m_OverrideState: 1
m_Value: 1
neutralHDRRangeReductionMode:
m_OverrideState: 0
m_Value: 2
acesPreset:
m_OverrideState: 0
m_Value: 3
hueShiftAmount:
m_OverrideState: 0
m_Value: 0
detectPaperWhite:
m_OverrideState: 0
m_Value: 0
paperWhite:
m_OverrideState: 0
m_Value: 300
detectBrightnessLimits:
m_OverrideState: 0
m_Value: 1
minNits:
m_OverrideState: 0
m_Value: 0.005
maxNits:
m_OverrideState: 0
m_Value: 1000
--- !u!114 &1943826748040886930
MonoBehaviour:
m_ObjectHideFlags: 3