티스토리 뷰
title: "1 주차"
category: SSU-Open-World
tags: [SSU, RPG, Soongsil-University, branch, directory, build, github-page]
date: "2021-03-08"
1 일차
Branch 구성
main | develop | feature |
---|---|---|
배포(Release) 버전 | 개발 버전 관리 | 디자인, 기능(?) 버전 관리 |
main branch에서 분기 | develop branch에서 분기 |
Directory 구성
- doc
- 개발 기록(
.md
) - uploads
- 이미지(
.png
,.jpg
,.gif
)
- 이미지(
- 개발 기록(
- dev
- unity project
- des
- blender
- substance painter
- release
- build files
2 일차
Branch 생성
- develop branch 생성
# git branch develop + git swtich develop git switch -c develop
- feature branch 는 Design 이 들어갈 때 생성할 예정
Unity Project 생성 및 빌드 테스트
- develop branch에서 Unity Project를 생성한다.
- Project name: ssu-rpg
- Template은
3D
- Github page로 Client를 구동할 예정이므로 환경은 WebGL.
release
폴더에 Build.- Test.
Only. release directory in main branch
main branch에는 오로지 배포 파일만 존재하도록 git 명령어 구성
- merge는 했지만 main branch에는 release directory만 존재
# main branch로 checkout git switch main # merge develop # option: --no-commit(merge OK but, 커밋 기록 X), --no-ff(fast-forward 하지 않기) git merge develop --no-commit --no-ff # release directory를 제외한 Unstage로 전환 # ssu-rpg directory를 Unstage로 전환 git reset ssu-rpg # Untrack에 대해서 working directory file 지우기 # option: -f(강제), -d(디렉토리 포함) git clean -fd # Modify에 대해서 되돌리기 # .은 하위 디렉토리 모두 포함 git restore .
main branch에는 release, doc directory만 존재하도록 함.
Github page로 build 파일 실행
Github page로 build파일 실행
- Github에서 해당 repository의 Settings
- Github Pages 설정
- Branch는 main.
- /(root) 설정.
3 일차: 2021-03-10
폴더 정리
- ResourcesUnity의 Load API를 사용하기 위해서는
Resources
이름의 폴더 하위로 접근 가능하므로 Art, Prefab 등은 해당 폴더 하위로 보관한다. - Scripts
- ControllersPlayer, Monster, NPC 등의 Controller
- Managers각종 Managers: Input, Data, UI, Scene 등을 모아둘 예정.
- UtilsEnum 값, Extension, Util(= 사용하면 유용할 함수) 등을 모아둘 예정.
- Test각종 Test Script 등 모아둘 예정.
- ...계속 추가될 예정.
- ...계속 추가될 예정.
Manager 생성
- Manager들은 모두 Singleton pattern 이용
Manager
- Manager만 MonoBehaviour 상속 받음
- InputManager 등 Input에 관한 Call-back 실행을 Manager의 Update()에서 실행
@Manager
라는 이름의 빈 GameObject로 Scene이 이동해도 삭제 못하도록 DontDestroyOnLoad() 이용- 여러 Manager를 호출 가능하도록
- Manager.Input: InputManager 호출
public class Manager : MonoBehaviour
{
// Singleton
static Manager _instance;
static Manager Instance { get { if (_instance == null) Init(); return _instance; } }
#region core
InputManager _input = new InputManager();
public static InputManager Input { get { return Instance._input; } }
#endregion
void Update()
{
// input의 Call-back을 실행시켜줌.
_input.OnUpdate();
}
static void Init()
{
GameObject go = GameObject.Find("@Manager");
if (go == null)
{
go = new GameObject() { name = "@Manager" };
_instance = go.AddComponent<Manager>();
}
// Scene이 이동해도 삭제 [X]
DontDestroyOnLoad(go);
}
}
InputManager
- 모든 Input을 관리할 예정.Mouse, KeyInput, Touch 등.
- MonoBehaviour를 상속받지 않고
Manager
에서Update()
에서 실행하도록 함.
public class InputManager
{
public Action<Define.MouseEvent> MouseAction = null;
float _pressedTime = 0f; // 잠깐의 짧은 클릭인 지 시간 체크
public void OnUpdate()
{
// Manager에서 Update 실행해줌.
if (MouseAction != null)
OnMouse();
}
public void Clear()
{
MouseAction = null;
}
#region Event
void OnMouse()
{
if (Input.GetMouseButtonDown(0))
{
// LMB: 0
MouseAction.Invoke(Define.MouseEvent.Down);
// 시간 측정
_pressedTime = Time.time;
}
else if (Input.GetMouseButton(0))
{
// LMB 누르고 있을 때
MouseAction.Invoke(Define.MouseEvent.Press);
}
else if (Input.GetMouseButtonUp(0))
{
// LMB 떼었을 때
if (Time.time - _pressedTime < Define.MousePressedTime)
MouseAction.Invoke(Define.MouseEvent.Click);
else
MouseAction.Invoke(Define.MouseEvent.Up);
}
}
#endregion
}
Player 움직이기
BaseConroller
를 작성해 움직이는 모든WorldObject
에 대해 기본 클래스를 작성- Monster, Player 등 모든 움직이는 WorldObject는
BaseController
Class를 상속받는다.
BaseController.cs
- 직접 Instance를 상속받을 수 없도록 abstract class
- 상속 받는 Controller.cs 는 OnStart(), OnUpdate()를 갖도록BaseController에서 MonoBehaviour를 상속 받기 때문에 모든 Controller는 Start(), Update()를 작성할 필요 [X]
Start()는 Unity의 Single-Thread의 실행 순서를 알 수 없으니 이를 이용.
public abstract class BaseController : MonoBehaviour
{
[SerializeField] protected Define.State _state;
[SerializeField] public Define.WorldObject WorldObjectType { get; protected set; }
void Start()
{
OnStart();
}
void Update()
{
OnUpdate();
}
protected abstract void OnStart();
protected abstract void OnUpdate();
}
PlayerController.cs
public class PlayerController : BaseController
{
Vector3 _destPos;
float _walkSpeed = 5f;
float _angularSpeed = 10f;
// Property를 이용해 State를 조작하는 순간 Animation 상태도 바뀐다.
public Define.State State
{
get { return _state; }
set
{
_state = value;
Animator anim = GetComponent<Animator>();
switch (_state)
{
case Define.State.Idle:
// anim.CrossFade("Idle", 0.1f);
break;
case Define.State.Walking:
// anim.CrossFade("Walk", 0.1f);
break;
case Define.State.Running:
// anim.CrossFade("Run", 0.1f);
break;
}
}
}
protected override void OnStart()
{
// Settings
_state = Define.State.Idle;
WorldObjectType = Define.WorldObject.Player;
// Listener
Manager.Input.MouseAction -= OnMouseEvent; // Pooling으로 인해 두 번 등록 방지
Manager.Input.MouseAction += OnMouseEvent;
}
protected override void OnUpdate()
{
// Update()
switch (_state)
{
case Define.State.Die:
UpdateDie();
break;
case Define.State.Idle:
UpdateIdle();
break;
case Define.State.Walking:
UpdateWalk();
break;
case Define.State.Running:
UpdateRun();
break;
}
}
#region UpdateState
void UpdateDie() { }
void UpdateIdle() { }
void UpdateWalk()
{
Vector3 dir = _destPos - transform.position;
if (dir.magnitude < 0.1f)
{
// 오차 범위 안쪽이면 도착
State = Define.State.Idle;
}
else
{
Debug.Log("이동중");
// 범위를 Clamp() 로 최대, 최소를 집어줌.
float moveDist = Mathf.Clamp(_walkSpeed * Time.deltaTime, 0, dir.magnitude);
// Position 이동
transform.position += dir.normalized * moveDist;
// Slerp 이용한 부드러운 방향 전환
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(dir), _angularSpeed * Time.deltaTime);
}
}
void UpdateRun() { }
#endregion
#region OnEvent
void OnMouseEvent(Define.MouseEvent mouseEvent)
{
if (_state == Define.State.Die)
return;
// Ray
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitInfo;
bool isHit = Physics.Raycast(ray, out hitInfo, 100f, LayerMask.GetMask("Ground"));
// Debug
Debug.DrawRay(Camera.main.transform.position, Input.mousePosition - Camera.main.transform.position * 100f, Color.green, 1f);
switch (mouseEvent)
{
case Define.MouseEvent.Down:
break;
case Define.MouseEvent.Press:
break;
case Define.MouseEvent.Up:
break;
case Define.MouseEvent.Click:
if (isHit)
{
Debug.Log($"이동! {hitInfo.point}");
_destPos = hitInfo.point;
State = Define.State.Walking;
}
break;
}
}
#endregion
}
Define.cs
- 여러 enum, const 상수를 정해줌.
C#
은#define
상수가 불가능
public class Define
{
#region MouserEvent
public const float MousePressedTime = 0.5f;
public enum MouseEvent
{
Down,
Press,
Up,
Click,
}
#endregion
#region State
public enum State
{
Die,
Idle,
Walking,
Running,
}
#endregion
#region WorldObjectType
public enum WorldObject
{
Unknown,
Player,
Monster,
}
#endregion
}
Build Test: 3 일차
- 모바일도 Mouse Click과 같은 Event 받는 것을 확인
- 모바일 Touch도 잘 된다는 뜻.
PC | Mobile |
---|---|
4 일차: 2021-03-11
모바일 미지원 알림 제거
Assets/Editor
에PostBuildAction.cs
작성- Bulid할 때, Call-back 으로 작용
using System.IO;
using UnityEditor;
using UnityEditor.Callbacks;
public class PostBuildAction
{
[PostProcessBuild]
public static void OnPostProcessBuild(BuildTarget target, string targetPath)
{
var path = Path.Combine(targetPath, "Build/UnityLoader.js");
var text = File.ReadAllText(path);
text = text.Replace("UnityLoader.SystemInfo.mobile", "false");
File.WriteAllText(path, text);
}
}
Scene Manage
SceneManagerEx.cs
- Scene Manager는 이미 Unity Engine에 있으므로 Scene Manager Extended 작성
- C# Reflection 이용한 Enum type name 추출
public class SceneManagerEx { public BaseScene CurrentScene { get { return GameObject.FindObjectOfType<BaseScene>(); } } public void LoadScene(Define.Scene type) { // 다른 Scene으로 움직이면 모든 Manager에 대해 Clear() Manager.Clear(); string sceneName = GetSceneName(type); SceneManager.LoadScene(sceneName); } public void Clear() { CurrentScene.Clear(); } string GetSceneName(Define.Scene type) { // Reflaction return System.Enum.GetName(typeof(Define.Scene), type); } }
BaseScene.cs
- 추상 클래스로 모든 Scene Script의 Base.
public abstract class BaseScene : MonoBehaviour { public Define.Scene SceneType { get; protected set; } = Define.Scene.UnKnown; void Awake() { OnAwake(); } protected abstract void OnAwake(); // Scene Manager에서 Load할 때 Clear() public abstract void Clear(); }
Camera Control
CameraController.cs
- LateUpdate()Player가 움직인 다음 Update() 되도록.
Unity 생명 주기 참고. - Player의 null 값 비교Destroy, SetActive false에 대해서 비교 가능하도록
public class CameraController : MonoBehaviour { // Player와 떨어진 거리 차 [SerializeField] Vector3 _delta = new Vector3(0, 5f, -10f); [SerializeField] GameObject _player = null; public GameObject Player { get { return _player; } set { _player = value; } } void LateUpdate() { // Unity Engine의 "null" 문자열 비교 이용 // Set Active: false에 대해서도 비교 if (!_player.IsValid()) return; // Camera의 Position은 _delta 만큼 차이나도록 매번 LateUpdate() transform.position = _player.transform.position + _delta; // Player를 항상 바라보도록 transform.LookAt(_player.transform); } }
- LateUpdate()Player가 움직인 다음 Update() 되도록.
좀 더 수정 필요
- PC 경우Wheel 로 확대 및 축소
- Mobile 경우두 손 Touch로 확대 및 축소
5 일차: 2021-03-12
Camera Zoom, Rotate: not yet
- 마우스 왼쪽 버튼으로 잡아 당기면 구 형태로 회전
void Rotate()
{
// 구현 아직...
}
- 마우스 휠로 Zoom in, Zoom out
void Zoom()
{
if (Input.mouseScrollDelta.y > 0)
{
// 축소
Debug.Log("축소");
// 구현 아직...
}
else if (Input.mouseScrollDelta.y < 0)
{
// 확대
Debug.Log("확대");
// 구현 아직...
}
}
6 일차: 2021-03-13
Mobile, PC 기기 구분
PC
vsMobile
PC
에서는Mouse
를 이용Mobile
에서는Touch
를 이용
- Click과 Touch의 인터페이스가 다르기 때문에
Mobile
과PC
구분은 필수! - Assets/Plugins/MobileOrPc.jslib
var MobileOrPc = {
isMobile: function () {
return UnityLoader.SystemInfo.mobile;
},
};
mergeInto(LibraryManager.library, MobileOrPc);
- Util.cs
- DLL 사용Unity를 Loading할 때, Mobile 확인
- Property로 접근
#if !UNITY_EDITOR && UNITY_WEBGL
[DllImport("__Internal")] private static extern bool isMobile();
public static bool IsMobile { get; } = isMobile();
#else
public static bool IsMobile { get; } = false;
#endif
7 일차: 2021-03-14
Camera Zoom, Rotate 계획
PC | Mobile | |
---|---|---|
Zoom | Mouse Scroll Wheel 이용 | 두 손가락 터치 간격으로 조절 |
Rotate | Left Mouse Button을 길게 누른 것을 이용 | 한 손 터치 길게 누른 것을 이용 |
728x90
반응형
댓글