도전과제를 모두 완성하고 리드미까지 작성을 완료했습니다.
스파르타 코딩클럽 10기, 유니티 입문 개인 프로젝트 스파르타 메타버스 만들기 과제작업물입니다.
void Update()
{
switch (State)
{
case Define.State.Idle:
UpdateIdle();
break;
case Define.State.Skill:
UpdateSkill();
break;
}
HandleAttackDelay();
}
private void FixedUpdate()
{
switch (State)
{
case Define.State.Moving:
UpdateMoving();
break;
case Define.State.Knockback:
UpdateKnockBack();
break;
}
// 점프 관련연산
UpdateJump();
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Door : MonoBehaviour, ITimeTriggerable
{
[SerializeField]
private string _targetScene;
[SerializeField]
private float _waitTime = 1.0f;
[SerializeField]
private Transform _pivot;
//같은 씬에서 이동할때
public bool isMoveInSameScene =false;
[SerializeField]
private Transform targetPositon;
[SerializeField]
private GameObject targetPivot;
CameraManager _camera;
private void Awake()
{
_camera = Camera.main.GetComponent<CameraManager>();
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.CompareTag("Player"))
{
RoomController controller = collision.GetComponent<RoomController>();
controller.StartTriggerCountdown(this,_waitTime, _pivot.position);
}
}
private void OnTriggerExit2D(Collider2D collision)
{
if (collision.CompareTag("Player"))
{
RoomController controller = collision.GetComponent<RoomController>();
controller.CancelTriggerCountdown();
}
}
// 콜백으로 호출되는 메서드
public void OnTriggerTimeComplete()
{
if(!isMoveInSameScene)
SceneManager.LoadScene(_targetScene);
else
{
_camera.ChangePivot(targetPivot);
LobbyScene.Instance.StartLogueGame(targetPositon);
}
}
}
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class ScoreBoard : MonoBehaviour
{
[SerializeField]
private string _scoreName;
[SerializeField]
private TextMeshProUGUI _scoreTxt;
private void Awake()
{
LobbyScene.OnScoreUpdate += UpdateScoreBoard;
}
public void UpdateScoreBoard()
{
_scoreTxt.text = PlayerPrefs.GetInt(_scoreName, 0).ToString();
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraManager : MonoBehaviour
{
[SerializeField]
private Transform target;
[SerializeField]
private float lerpSpeed = 5f;
[SerializeField]
private Vector3 offset;
[SerializeField]
private GameObject cameraPivot;
private float minX = 0;
private float maxX = 0;
private float minY = 0;
private float maxY = 0;
public bool isFixedY = false;
private void Awake()
{
ChangePivot();
}
public void ChangePivot(GameObject targetPivot = null)
{
if(targetPivot == null)
{
cameraPivot = LobbyScene.Instance.baseMap;
}
else
{
cameraPivot = targetPivot;
}
// 카메라 경계 지정 함수, 추후 별도의 함수로 만들어야함
// 맵로드 이후 피벗 설정
if (cameraPivot != null)
{
GameObject leftUpPivot = cameraPivot.transform.GetChild(0).gameObject;
GameObject rightDownPivot = cameraPivot.transform.GetChild(1).gameObject;
float camHalfHeight = Camera.main.orthographicSize;
float camHalfWidth = camHalfHeight * ((float)Screen.width / Screen.height);
minX = leftUpPivot.transform.position.x + camHalfWidth;
maxX = rightDownPivot.transform.position.x - camHalfWidth;
minY = rightDownPivot.transform.position.y + camHalfHeight;
maxY = leftUpPivot.transform.position.y - camHalfHeight;
}
}
private void LateUpdate()
{
if (target == null) return;
Vector3 destinationPosition = target.position + offset;
Vector3 lerpPosition = Vector3.Lerp(transform.position, destinationPosition,
lerpSpeed * Time.deltaTime);
if (cameraPivot != null)
{
lerpPosition.x = Mathf.Clamp(lerpPosition.x, minX, maxX);
lerpPosition.y = Mathf.Clamp(lerpPosition.y, minY, maxY);
}
if(!isFixedY)
transform.position = lerpPosition;
else
transform.position = new Vector3(lerpPosition.x, transform.position.y, transform.position.z);
}
}
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
public class DataManager : MonoBehaviour
{
public static DataManager instance;
private void Awake()
{
if (instance == null)
instance = this;
}
public void Save(string[] animatorAddresses, string savePath)
{
var dataList = new AnimatorSaveDataList();
foreach (var addr in animatorAddresses)
dataList.animators.Add(new AnimatorSaveData { animatorAddress = addr });
string json = JsonUtility.ToJson(dataList, true);
File.WriteAllText(savePath, json);
}
public string[] Load(Animator[] targetAnimators, string savePath)
{
if (!File.Exists(savePath))
{
Debug.LogWarning("저장 파일이 없습니다.");
return null;
}
string json = File.ReadAllText(savePath);
var dataList = JsonUtility.FromJson<AnimatorSaveDataList>(json);
if (dataList.animators.Count != targetAnimators.Length)
{
Debug.LogError("Animator 개수 불일치");
return null;
}
for (int i = 0; i < dataList.animators.Count; i++)
{
string addr = dataList.animators[i].animatorAddress;
var animator = targetAnimators[i];
Addressables.LoadAssetAsync<RuntimeAnimatorController>(addr).Completed += handle =>
{
if (handle.Status == AsyncOperationStatus.Succeeded)
animator.runtimeAnimatorController = handle.Result;
else
Debug.LogError($"Animator {i} 로드 실패: {addr}");
};
}
// 주소만 추출해서 반환
return dataList.animators.Select(a => a.animatorAddress).ToArray();
}
}
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class DialogueEntry
{
public string key;
[TextArea]
public string text;
}
[CreateAssetMenu(menuName = "Data/NPCDialogue")]
public class DialogueData : ScriptableObject
{
public string npcId;
public List<DialogueEntry> data;
}
TextRpg/
├── Data/
│ ├── DataManager.cs
│ ├── DialogueData.cs
│ ├── PlayerData.cs
│
├── Database/
│ └── SlotDataManager.cs
│
├── GameLogic/
│ ├── Creature/
│ │ ├── Enemy/
│ │ │ ├── EnemyController.cs
│ │ │ └── EnemyStatHandler.cs
│ │ ├── Player/
│ │ │ ├── PlayerController.cs
│ │ │ ├── PlayerStatHandler.cs
│ │ │ └── RoomController.cs
│ │ ├── BaseController.cs
│ │ ├── ResourceController.cs
│ │ └── StatHandler.cs
│ │
│ ├── NPC/
│ │ ├── BaseNpc.cs
│ │ ├── ChangePlayerNpc.cs
│ │ ├── DialogueNpc.cs
│ │ ├── MiniGameNpc.cs
│ │ ├── NpcDialogueController.cs
│ │ └── RogueNpc.cs
│ │
│ ├── Weapon/
│ │ ├── InteractiveController.cs
│ │ ├── ProjectileController.cs
│ │ ├── RangeAttackController.cs
│ │ ├── RangeWeaponHandler.cs
│ │ └── WeaponHandler.cs
│
├── Manager/
│ ├── CameraManager.cs
│ └── RoundManager.cs
│
├── Map/
│ ├── Door.cs
│ ├── ITimeTriggerable.cs
│ ├── ScoreBoard.cs
│ ├── Result.cs
│ ├── ResultAttack.cs
│ ├── ResultHealth.cs
│ ├── ResultProjectileCount.cs
│ ├── ResultSpeed.cs
│ └── RogueDoor.cs
│
├── Scene/
│ ├── LobbyScene.cs
│ └── LogueGameScene.cs
│
├── MiniGame/
│ ├── Player/
│ │ └── Player.cs
│ ├── UI/
│ │ └── MiniGameUI.cs
│ ├── Wall/
│ │ ├── BgLooper.cs
│ │ └── Obstacle.cs
│ └── MiniGameScene.cs
│
├── Utils/
│ └── Define.cs