반응형

네트워크 RPG게임 'Raid' 개발일지 8


한달동안 꾸준히 만들고 있었다. 개발일지를 작성하기 귀찮았던 것도 있었지만 워낙 여기저기 코드 내부를 바꾼게 많다보니 막 정리하기 쉽지 않았다... 그래도 가장 큰 추가 및 수정 사항을 정리해면 다음과 같다.


1. 서브몬스터 완성

총 3개의 서브몬스터, EnemyNormal를 완성시켰다. 기존 EnemyBoss와 같은 클래스(Enemy Movement, Enemy Manager, Enemy Health, 등등)를 공유하기 때문에 네트워크에 instantiate했을때 InGame Manager에서 Enemy Type을 결정한 후 리스트에 추가하는식으로 구성되어있다.

서브몬스터 같은 경우 기존 Boss와 움직임이 다른데 InGame Manager에서 관리는 구역 A0~A4 에 따라 서로 다른 Patrol Point을 왔다갔다 한다. 이때 플레이어가 충분히 가까워지면 플레이어를 쫓아가게끔 구성했다. 또 플레이어가 일정 범위이상 멀어지면 다시 Patrol Point 사이를 랜덤으로 움직인다.



2. 구역 설정

맵을 보면 총 구역이 6개로 나뉜다. 시작지점인-A0, 일반스테이지인-A1~A3, 보스스테이지인-A4, 그리고 보너스 지역 S0이다. 각각 구역을 클리어 할 시 다음 지역으로 나아갈 수 있다.



3. 네트워크 관련 부분 대응
사실 이 부분이 가장 많이 어려웠다. 여러 클라이언트중 하나만 Master Client이기때문에 이 Master Client가 나가면 다시 설정해줘야하는 부분들이 많다. (Master Client가 기본적인 게임 진행을 이끄는 부분이 많다) 또한 공격처리하는 부분의 경우 각각의 클라이언트에서 처리하기 때문에 이 처리한 결과를 동기화시켜줘야 하는 방식이다. 어쨋든 게임 구조가 복잡해질 수록 자꾸 헷갈린다... (단순하게 모든 오브젝트들을 Network Instantiate할 수는 없는 노릇이다...) 게임이 복잡해질수록 스파케티코드가 되는것 같은 느낌이 든다... 이래서 클래서 구조가 중요한건가?...ㅎㅎ


4. 메쉬 컴바인(Mesh Combine/Bake)

모바일 게임이다 보니 최적화를 위해 하나의 게임오브젝트로 맵의 Mesh Object들을 에셋을 활용하여 컴바인했다. 메쉬를 컴바인하니 Batch수가 확실히 많이 줄어들었다.


반응형
반응형

네트워크 RPG게임 'Raid' 개발일지 7


오랜만에 개발일지를 올린다! 아예 손놓고 있었던건 아닌데 이것저것 하다보니까 이 프레젝트에 신경을 덜 쓰게 되었다...

지난번과 가장 크게 달라진 점은 맵 변경 및 스테이지 추가이다. 기존에는 보스와 대전이 바로 시작되는 방식이었지만 프로젝트 루와 비슷한 부분도 있고 네트워크 게임 치고 단조롭게 느껴져 기존 방식을 바꾸기로 했다.


1. 스테이지 형식의 맵

하나의 단순한 맵에서 스테이지 형식의 맵으로 바꾸었다. 서브구역을 다 통과하면 보스 구역으로 가는 방식으로 할 예정이다.


2. 서브 몬스터 추가

스테이지 형식이다보니까 각각의 구역에 서브 몬스터를 추가할 예정이다. 구역에 있는 모든 서브 몬스터를 다 처지하면 다음 구역으로 가는 방식으로 구성할 생각이다






반응형
반응형

네트워크 RPG게임 'Raid' 개발일지 6


정말 오랜만에 레이드 개발일지를 올린다!

5번째 개발일지를 올린지 벌써 2주가 되었다...

핑계를 대자면 방학이지만 아르바이트, 계절학기 까지 있다보니까 생각보다 시간이 없다... ㅠㅠ

또 최근에는 루 업데이트 및 최적화하는데 재미(?)가 들려서 이 프로젝트에 조금 소흘해진건 사실이다...

현재는 루 업데이트가 어느정도 만족스럽게 이루어졌고 이제 다시 레이드에 집중할때가 된것 같아서 다시 시작하게 되었다.


일단 가장 큰 업데이트 사항은 보스에 여러가지 공격 패턴을 만들었다

지금은 총 4개의 공격패턴을가지고 있다.

지금 현재 공격 자체가 조금 단순한 느낌이 없지않아 있는데 앞으로 좀 더 다이내믹하게 수정할 생각이다.




앞으로 계획은 다음과 같다

1. 공격패턴 추가 및 다이내믹하게 변경!  (이게 가장 중요한데 난이도가 가장 높을것 같다)

2. 맵 다시 제작 후 Mesh Bake해서 최적화

3. 게임 State 추가 : 현재는 바로 시작하는 형태지만 이제는 시작/게임중/게임종료등의 State를 넣어야한다. 플레이어 모두가 들어오면 시작하고 모두 죽었을시 게임 종료하는 형식으로 현재는 생각하고 있다.

4. 카메라: 좀더 부르덥게 회전 그리고 상하로 스와프시 카메라의 높이까지 변경




반응형
반응형

네트워크 RPG게임 'Raid' 개발일지 5


어제 드디어 학교 시험이 모두 끝났다!! 

이제 한학기 남았다 ... 드디어!!


오늘은 오랜만에 코딩하느랴 익숙해지는데 조금 시간이 걸렸다

하루종일 컴퓨터 앞에 있었는데도 생각보다 많은것을 구현하지는 못했다

내일은 더 분발해야지... :)


오늘 개발내용을 정리하면


1. 맵에 collider, navmesh 적용

그전에는 겉모습만 있고 collider나 navmesh bake을 하지 않았는데 이번에는 적용을 했다.

근데 솔직히 현재 제작한 맵이 마음에 들지 않기 때문에 나중에 다시 다 수정해야할것 같다


2. player <-> enemy간 아주 기본적인 Interaction 상호작용 완성

서로 때릴수 있고 맞으면 체력이 단다. (플레이어는 맞으면 넘어진다)

말로는 간단해 보이지만 사실상 제일 시간많이 걸린곳이다...

(네트워크 오브젝트간 RPC다루는 부분이기 떄문에...) 


3. Enemy Player Detection 수정

기본적으로 일직선 Ray 방식이었는데 판정이 너무 까다로워서(?) Physics.SphereCast 로 바꿨다


4. Enemy Attack 공격 범위 표시

공격범위 표시를 Projector로 구현했다

현재는 공격의 종류와 상관없이 전방에 공격한다... 

이때 공격하기 전에 Projector로 원을 그리면서 타격받을 수 있는 공간을 표시한다

(나중에 스킬별로 다 바꿔야한다)






네트워크 게임이다보니까 디버깅하는게 확실히 싱글플레이어 게임보다 까다롭고 귀찮다...

깃허브에 commit한후에 맥북프로 프로젝트를 다시 받고 두 컴퓨터에 번갈아가면서 테스트를 하지만

이 과정에 생각보다 너무 오래걸린다... ㅠ ㅠ

또 클라이언트 하나에서는 잘 되던게 동시에 두개에 하면 안되거나 이상한 버그가 생각보다 많이 발생한다...


원래 목표대로라면 1,2달 안에 프로젝트를 끝낼려고 했는데 할 수 있을지 모르겠다

알고리즘 공부도 이 프로젝트를 진행하면서 상당히 소흘해졌다. 따로 문제풀이도 해야하는데...

아무튼 더 열심히 해야하는건 확실한것 같다!



반응형
반응형

네트워크 RPG게임 'Raid' 개발일지 4


다음주부터 시험기간이라 당분간(2주 정도) 쉴것 같다...



-임시로 맵을 만들어 봤다. 콜라이더나 Navigation Bake은 되지 않은 상태이다.

-적의 움직임 + 공격을 조금더 자연스럽게 수정했다

-적에게는 4가지의 공격 패턴이있다. 현재는 애니메이션만 있다

-플레이어에 구르기 스킬을 추가 적용했다

-Game Manger에 Game State상태를 넣어 이제는 승리시  Victory Panel이 팝업된다.


반응형
반응형

네트워크 RPG게임 'Raid' 개발일지 3


며칠 동안 아주 열심히(?) 만들었다

중간에 작업한부분 날려서 멘붕한적도 있었지만 다행이 열심히 복구에 성공했다...

(참고로 깃허브 데스크탑으로 맥북프로에 작업물 연동하다 날려버림...)

그동안 작업 내용을 꾸준히 메모장엔 적고 있었는데 개발일지 쓰기가 귀찮아서 계속 미뤘다...

계속 미루다가는 안되겠다 싶어서 적는다


요 며칠동안 네트워크 부분을 가장 많이 다듬었다...

내가 생각했던 것보다 네트워크게임이 신경써야될 부분이 많고 스크립트 구조가 엄청 중요한것 같다.

특히 local player에 대한 서버처리를 어떻게 할것인가 고민을 많이 했다...

RPC사용, PhotonView.IsMine 처리, 데이터 동기화 때문에 기존에 만들었던 게임에 비해 난이도가 확실히 높다



위에는 윈도우데스크탑에서

아래영상은 맥북프로에서 실행한 영상이다.

영상으로 보면 알 수 있겠지만 정상적으로 동기화가 되며

혼자서 동시에 컨트롤(?)하다보니 움직임이 조금 이상해 보일 수 있지만 큰 문제점은 현재까지 없다.


게임에는 총 2명의 player 그리고 1마리의 보스가 존재하는데 현재 보스는 접속한 player를 랜덤으로 쫓아가게끔했다. 

물론 지금 animation도 그렇고 보스 패턴 알고리즘을 만들고 있는중이라서 걷는 모습이나 쫓아가는 모습이 조금 어색해 보인다 ...ㅎ

다행이 네트워크쪽으로 이상한 부분은 발견하지 못했다. (한쪽 클라이언트에서만 스킬이 발동한다던가 등등...)





반응형
반응형

네트워크 RPG게임 'Raid' 개발일지 2


개발시작 후 4일차인가 5일차이다.

오늘 하루 나름 탄력 받으면서 개발을 진행할 수 있었다 :)

하루동안 너무 많은걸 만들다보니 여기에 다 제대로 정리할 수 있을지 모르겠다!

아무튼 오늘 구현한것들을 최대한 정리해보면


1) Touch Screen Rotation (터치에 의한 화면 회전)

저번에 카메라가 바라보는 방향에 따라 케릭터가 움직이도록 구현을 했다. 

이번에는 터치값을 받아 카메라를 집접 회전시킬수 있도록 구현을 했다.

정리를 하자면 오른쪽으로 스와프하면 카메라가 오른쪽으로 회전하고 왼쪽으로 스와프하면 왼쪽으로 회전한다


2) GameData.cs  DataManger.cs 추가 : 로컬 데이터 매니징 스크립트 제작

데이터값을 담는 스크립트와 그 데이터값을 불러오거나 수정하는 로컬 매니저를 만들었다. 


메모: [Serializable] / [NonSerialized] 태그를 넣어서 나중에 데이터파일을 JSON으로 파싱할때 모든 데이터값들을 다 파싱하지 않게 한다. 이게 왜 필요하냐면 나중에 게임 패치를 할때 기존의 Serialized된 값이면 패치 내용을 덮어씌워서 옛날값을 읽어버리기 때문에 곤란해진다...


3) Start Game UI 

이제 직업을 고르고 GameData에 저장을 한 후 InGame Scene에 들어가 내가 고른 직업에 따라 케릭터가 Spawn 된다.





4) 애니메이션 추가

앞으로 추가할 애니메이션이 엄청나게 많지만 일단 각각의 직업(클래스) 별로 공격 애니메이션 하나 추가했다.

메모: 생각보다 애니메이션부분이 실제 이동, 버튼클릭과 연동되면서 버그가 많이 발생하는것 같다... 구조를 잘짜야한다...




이 이외에도 그래픽 및 디자인적인 부분을 많이 수정했다.

디자인을 바꾸니 이전과 눈에 띄게 차이가 나서 뭔진 몰라도 많은걸 이룬것 같아서 상당히 뿌듯했다.....ㅎㅎ




5) 전체적인 UI스킨 적용

디자인적인 부분은 항상 고민하고 있었다.

아무리 훌륭한 코딩을 할수 있어도 겉모습이 별로면 뭔가 게임의 질이 떨어져 보이는것 같다.

지금까지 게임을 만들면서 UI같은경우 스킨을 적용한적이 없다.

그러다보니 항상 Flat하고 단조로운 느낌이 없지않아 있다.

그래서 이번에 처음으로 UI스킨을 구입해서 적용했는데 그럴사에 보인다.

Tweening 동작들은 나중에 마지막에 하려고 한다...





6) Toon Shader 적용

기존의 케릭터가 조금 어색한것 같아서 쉐이더를 바꿔줬다

Toony Colors Pro 2라는 에셋을 사용했는데 정가가 $40나한다... (다행히 지금 세일해서 $20에 샀다ㅎㅎ)

적용하면 뭐 얼마나 달라질까 의심했지만 확실히 더 좋아진것 같다... 

이게 말로 설명하기 힘든데 확실히 더 자연스럽다...






-영상을 보면 알 수 있겠지만 클래스 3가지 선택가능하다

-UI스킨을 적용하니 상당히 이쁘다 ... 완성하면 꽤 괜찮은 퀄리티 나올수도?

-화면 회전도 정상적으로 작동한다

-이제는 이동 모션 + 공격 모션까지 할 수 있다

-현재는 이미지만 있고 사용 못하는 기능들이 많다. 언젠간 다 만들겠지?







반응형
반응형


네트워크 RPG게임 'Raid' 개발일지 1

사용엔진: Unity 2017.3

요즘 PUN(포톤 유니티 네트워크), Photon(포톤) 이라는 네트워크 솔루션을 활용하여 3D Multiplayer RPG스타일의 게임을 만들고 있다.

일단은 가제목을 Raid로 했는데 나중에 바꿀수도 있을것 같다.


Player의 움직임 스크립트를 짜고있는 와중에 카메라를 기준으로 플레이어의 움직임을 어떻게 구현할까 궁굼했는데

구글링을 열심히 한 결과 Joystick을 활용하여 카메라가 바라보는 기준으로 앞으로 나가겠금 구현을 하는데 성공했다.

혹시 나중에 쓸 수도 있으니 여기에 스크립트 일부를 올려야겠다.

아직 전혀 다듬지 않은 스크립트이기 때문에 나중에 리팩토링하는 시간을 가져야겠다.


-핵심 스크립트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void Move(float hor, float ver)
    {
        Vector3 targetDirection = new Vector3(hor, 0f, ver);
        targetDirection = CameraManager.instance.cVC.transform.TransformDirection(targetDirection);
        targetDirection.y = 0.0f;
        movement = targetDirection.normalized * playerSpeed * Time.deltaTime;
        playerRigidbody.MovePosition(transform.position + movement);
    }
    void Turn(float hor, float ver)
    {
        if (!acting)
            rotationSpeed = ROTATION_DEFAULT + 1f;
        else
            rotationSpeed = ROTATION_DEFAULT - 1f;
        Vector3 targetDirection = new Vector3(hor, 0f, ver);
        targetDirection = CameraManager.instance.cVC.transform.TransformDirection(targetDirection);
        targetDirection.y = 0.0f;
        Quaternion targetRotation = Quaternion.LookRotation(targetDirection, Vector3.up);
        Quaternion newTargetRotation = Quaternion.Lerp(playerRigidbody.rotation, targetRotation, rotationSpeed * Time.deltaTime);
        playerRigidbody.MoveRotation(newTargetRotation);
    }
cs



-전체 스크립트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
 
public class PlayerMovement : MonoBehaviourPun
{
    private Vector3 movement;
    private Rigidbody playerRigidbody;
    public float playerSpeed;
    public float rotationSpeed;
    private float h;
    private float v;
 
    public bool moving; //basic movement
    public bool acting; //dash , skill attacks, etc
    public bool tumbled; //tumbled when hit by enemy
    public bool alive;
 
    private const float SPEED_DEFAULT = 5f;
    private const float ROTATION_DEFAULT = 4f;
    private const float ADDFORCE_DEFAULT = 1000f;
 
    public static bool controllerActive;
 
    void Awake()
    {
        playerRigidbody = this.gameObject.GetComponent<Rigidbody>();
    }
 
    void Start()
    {
        controllerActive = true;
        alive = true;
        playerSpeed = SPEED_DEFAULT;
        rotationSpeed = ROTATION_DEFAULT;
    }
 
    void Update()
    {
        if (photonView.IsMine == false && PhotonNetwork.IsConnected == true)
            return;
 
        if (controllerActive)
        {
            if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer)
            {
                h = JoystickManager.instance.x;
                v = JoystickManager.instance.y;
            }
            else //for PC in editor
            {
                if (JoystickManager.instance.joystickActivation == true)
                {
                    h = JoystickManager.instance.x;
                    v = JoystickManager.instance.y;
                }
                else
                {
                    h = Input.GetAxisRaw("Horizontal");
                    v = Input.GetAxisRaw("Vertical");
                }
            }
        }
    }
 
    void LateUpdate()
    {
        if (photonView.IsMine == false && PhotonNetwork.IsConnected == true)
            return;
 
        if (alive && controllerActive)
        {
            if (h != 0 || v != 0)
            {
                if (!tumbled)
                {
                    moving = true;
                    Move(h, v);
                    Turn(h, v);
                }
            }
            else
            {
                moving = false;
            }
        }
    }
 
    void Move(float hor, float ver)
    {
        Vector3 targetDirection = new Vector3(hor, 0f, ver);
        targetDirection = CameraManager.instance.cVC.transform.TransformDirection(targetDirection);
        targetDirection.y = 0.0f;
        movement = targetDirection.normalized * playerSpeed * Time.deltaTime;
        playerRigidbody.MovePosition(transform.position + movement);
    }
 
    void Turn(float hor, float ver)
    {
        if (!acting)
            rotationSpeed = ROTATION_DEFAULT + 1f;
        else
            rotationSpeed = ROTATION_DEFAULT - 1f;
 
        Vector3 targetDirection = new Vector3(hor, 0f, ver);
        targetDirection = CameraManager.instance.cVC.transform.TransformDirection(targetDirection);
        targetDirection.y = 0.0f;
        Quaternion targetRotation = Quaternion.LookRotation(targetDirection, Vector3.up);
        Quaternion newTargetRotation = Quaternion.Lerp(playerRigidbody.rotation, targetRotation, rotationSpeed * Time.deltaTime);
        playerRigidbody.MoveRotation(newTargetRotation);
    }
    
}
cs



-이번 프로젝트에서는 Unity의 Camera로 Cinemachine을 사용했는데 상당히 괜찮은것 같다 (그전에 유니티 5.6에서 작업했을때는 사용불가...)

-기본적인 포톤네트워크 접속 셋팅이 어느정도 된 상태이다. (밑에 동영상을 보면 서버처리 없이 그냥 Local에서 Instantiate한것 처럼 보이는데 

사실 네트워크처리에 의해  PhotonNetwork.Instantiate이 된거다 )


반응형

+ Recent posts