본문 바로가기

Photon

Photon 다섯 째날 (RPC로 OnDamage, RPC.애니메이션(상태머신), RPC.총,Connection Scene UI 꾸미기)

목차


RPC 를 이용해서 맞은 Player 데미지 깎이게 하기

 

Photon View 를 이용해 서버에 위치를 전송해줌 RPC 를 이용해서

데미지 가한것을 서버에 전송해서 다들 Damage 깎이게 한거임

 

RPC 는 모든 PC 에 붙어있긴 한데, 

photonView 의 ID 는 다 다르다.

 

맞은 Player의 데미지를 달게 하기위해, PlayerFire 로 간다 --->

RPC 를 이용해서 총알 발사

총알 생성한 부분을 RPC 로 빼서  넣는다.

 

이 부분도 RPC 로 해보자

OnDamaged 에 들어가서 그 안에있는것도 뺴서 Rpc 형태로 바꾸자

이렇게 OnDamaged 자체를 RPC 로 바꾸면 됨

이 함수는 맞은애의 PhotonView 에서 터지는거임

 

근데 여기서 문제가 Destroy 도 따로 해줘야함 해주는 방법이 있음

 

이게 Destroy 되면 카메라가 그냥 없어져버리니까 그게 문제인거임

-> Destroy 가 되면 파괴할 수도 있긴한데 , Player 가 중천을 떠돌면서 상황을 바라보게 하는게 더 나음

보통게임이 그렇기도 함


RPC 를 이용해서 애니메이션 구현하기

이거 Import 하기
새로 생성

Player에게 넣은 프리팹에서 Animator 부분에 우리가 만든 Animator 를 넣는다

PlayerAnim(Animator) 에서 만들어줌
애니메이션 만들어준 모습
만든 Parameter 3개

AnyState => Shoot ()

trigger -> Fire ,(HasExitTime x)

 

Shoot => Idle 

(HasExitTime O)

 

Idle => Run

trigger -> Move, (HasExitTime X)

 

Run => Idle

trigger -> Idle , (HasExitTime X)


애니메이션 상태머신 스크립트 만들기

 

PlayerState.cs 스크립트 파일 만들어줌

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerState : MonoBehaviour
{
    // 플레이어 상태 Enum
    public enum State
    { 
        IDLE,
        MOVE,
        DIE
    }

    // 현재 상태
    public State currState;

    //Animator
    public Animator anim;


    // 상태 변경 함수
    public void ChangeState(State s)
    {
        // 현재 상태를 s상태로!
        currState = s;
        // 상태에 따라서 animation 처리
        switch (currState)
        {
            case State.IDLE:
                anim.SetTrigger("Idle");
                break;
            case State.MOVE:
                anim.SetTrigger("Move");
                break;
            case State.DIE:
                break;
        }
    }

Enum 과 Switch 문을 통해서, 애니메이션을 나눈다

 

그러면 이제 PlayerMove 로 와서

PlayerState 컴포넌트 받아오고
h,v 값에 따라서 상태바꿔줌
Player에게 붙이자

Player State 스크립트를 Player 에게 붙인다.

Anim 에는 건담프리팹을 넣어주면 됨

 

여기서 문제, animation 은 트리거가 계속나오게 되면 문제가 됨.

지금 Idle 이 계속 Update 에서 트리거가 계속 불림

(움직이지 않으면 Trigger 가 계속 불린다.

이렇게 되면 다른 애니메이션이 진행되도 Idle 이 불릴때가 있는 문제가 발생한다)

 

PlayerState 에서 함수 추가

PlayerState 에서 

if(currState == s)

return;

코드를 추가 시켜준다.

 

그러면 스테이트가 한번만 불리고 같은 State 일 경우 ChangeState 는 더이상 불리지 않는다!

 

(참고) 이전상태로 돌아가고 싶을 때는 어떻게?

더보기

State prevState 를 만들어서 currState 를 저장해놓고 또 쓸 수 있음

이제 애니메이션까지는 완성 했는데, 다른사람은 안보임! 

그러니까, Pun 을 사용하자

 

PlayerState 에서 Rpc 를 만들거니까, Photon.Pun 네임스페이스 추가 하자

    // 상태 변경 함수
    public void ChangeState(State s)
    {
        // 현재상태가 s와 같다면 함수를 나가라.
        if (currState == s) return;

        // 현재 상태를 s상태로!
        currState = s;
        // 상태에 따라서 animation 처리
        switch (currState)
        {
            case State.IDLE:
                photonView.RPC("RpcSetTrigger", RpcTarget.All, "Idle");
                break;
            case State.MOVE:
                photonView.RPC("RpcSetTrigger", RpcTarget.All, "Move");
                break;
            case State.DIE:
                break;
        }
    }

    [PunRPC]
    void RpcSetTrigger(string s)
    {
        anim.SetTrigger(s);
    }

 

이렇게 되면, Rpc 로 애니메이션 같이 연동 됨!


RPC 로 총 쏘게 하기

PlayerFire 에서 

 

RPC 는 PhotonView 가 같은라인에 있으면 Pun 함수를 다 불러올 수가 있음

그니까, PunRPC 가 다른 스크립트에서 쓰인 함수도 다 들고올 수 있음

Player한테 붙이자

 

    void FireRay()
    { 
            //2. 카메라 중심, 카메라 앞방향 에서 Ray를 생성
            Ray ray = new Ray( Camera.main.transform.position , Camera.main.transform.forward );
            //3. 생성된 Ray를 발사해서 어딘가에 부딪혔다면
            RaycastHit hit;
        if (Physics.Raycast(ray, out hit))
        {
            //맞은애 한테 PlayerMove들고와서 함수 실행!
            PlayerMove pm = hit.transform.GetComponent<PlayerMove>();
            if (pm)
                pm.OnDamaged();

            // 서버에 접속되어있는 모든 PC 에 요청
            // 근데 모든 PC 에 붙어있는거임. 거기 중에,
            // 같은 photonView ID 를 가지고있는 애가 실행되게 해주는거임
            photonView.RPC("RpcShowBulletImpact", RpcTarget.All, hit.point, hit.normal);
        }
        else
        {
            //총소리 -> 동기화
            // PlayOneShot 은 또 쏴도 끝까지 플레이하고 다시 시작하게 됨
            photonView.RPC("RpcBulletSound", RpcTarget.All);
        }
        //총쏘는 애니메이션
        photonView.RPC("RpcSetTrigger", RpcTarget.All, "Fire");
    }

    [PunRPC]
    void RpcBulletSound()
    { 
            bulletSound.PlayOneShot(bulletSound.clip);
    }

    [PunRPC]
    void RpcShowBulletImpact(Vector3 point, Vector3 normal)
    {
        //4. bulletImpact 효과를 만든다.
        GameObject bulletImpact = Instantiate(bulletImpactFactory);
        //5. 만든효과를 부딪힌 위치에 놓는다.
        bulletImpact.transform.position = point;
        //6. 만든효과의 앞방향을 normal 방향으로 한다.
        bulletImpact.transform.forward = normal;
        //7. 2초뒤에 파괴 한다.
        Destroy(bulletImpact, 2);
    }

 

PlayerFire 를 RPC 로 고친모습


RPC로 Die 상태로 바꾸기

 Die 상태가 되면 모델과 컴포넌트를 꺼주자

(카메라만 키게 만들겠다는 거임)

 

배열 선언해서, 배열에 들어있는것들 다 끄겠다는거임

 

PlayerState ---->

변수 설정

MonoBehaviour 가 부모 이기 때문에 저렇게 넣을 수 있은거임

PlayerState 에서 Die 일 때, 게임오브젝트 다 끄고, 컴포넌트는 다 enabled = false 해줌

배열에 Assign 해주자

 

그러면 PlayerMove.cs 에서

Destroy 를 없애고, PlayerState를 DIe 로 바꿔준다.

이건 이미 PunRPC 안에있는거기 때문에 이걸 따로 RPC 로 안만들어줘도 된다.


지금 Bullet 이 파괴 되는게 내 컴퓨터에서만 파괴 될 텐데,

 

네트워크에서 OnTrigger 를 관리 하게 되면

네트워크의 지연이 일어나면 누구는 맞고 누구는 안맞을 수도 있다.

그러니까, 내가 모든걸 관리 할 거임

내 컴퓨터에서 Destroy 되면 그걸 서버에 올릴거란 얘기

 

Bullet.cs --->

내 컴퓨터 에서만 파괴할 거임

내 총알이면 파괴 하게 만듦

 

근데 여기서 문제..

언제는 둘다 폭발효과가 일어나고, 하나는 안일어남

 

=> 부딪히기 전에 PhotonNetwork.Destroy(gameObject) 이 일어나서 상대방의 컴퓨터에서는 안보이는거임

그니가 부딪히기도 전에 없어져 버린거임. 게임오브젝트가.

 

다른 사람은 충돌처리 할 필요도 없이 한명이 폭발 하라고 시키면 다 폭발일어나게 하면 됨.

그래서 한명이 충돌처리를 다 하게 하면 됨.

 

 

RPC 로 Destroy 시켜도 상관없는데, 주인이 한방에 다 파괴 할 수 있다.

 

그니까, Bullet.cs 스크립트 ---->

Bullet Collider 끈다
내꺼면 Collider 키고, 아니면 RIgidBody 를 삭제할 거임

그니까 애초에 Collider 꺼놓고 있겠다는거고,

다른사람 컴퓨터에서는 안부딪혀도 상관없음

 

내 컴퓨터에서 부딪히면, 그걸 서버에 올릴거니까

TriggerEnter 도 RPC 로 만든다.

원래 TriggerEnter 에 있던거를 RPC 에 넣는다

 

position 은 바꿔준 모습

이렇게 해주면,

내총알이 Trigger 가 되서 다른 컴에는 효과가 다 같이 나오고,

 

파괴 하는것만 내 컴퓨터 에서 해주고 이 사실을 서버에 다 뿌려서

다른 컴에도 파괴 되게 하는거임

 

이렇게되면 효과가 나오기 전에 파괴되는 일이 없는거임

RPC 로 호출되기 때문에, 

이거랑 같다. 다를 바 없다.

그냥

1. Destroy 를 해주는거나

2. photonView.IsMine 일때 PhotonNetwork.Destroy 해주는거나 똑같다.

 

1번은 다 알다시피 내꺼만 Destroy 해주는거고

 

2번에 PhotonNetwork.Destroy(gameObject)는 모든 게임오브젝트(Player) 다파괴하는거다. 근데 내꺼일 때만 파괴하는거니까 결국 내꺼만 파괴되는것임

 

그냥 보여주기 위해서 한거임

IsMine 이면 나 자신을 파괴 하게 한거임


Connection  Scene 간단하게 꾸미기

ConnectionManager.cs 에서 시작 ㄱㄱ

 

Start 에 있던 코드를

함수로 뺀다

버튼 클릭하면 이게 실행되게 할 거임
ConnectScene 에서 InputField 와 Button 을 만들자.

이렇게 하면 Screen Size 에 맞춰주는거임

800,600 으로 맞춰주자

Main Camera 에서 Soild Color 로 맞춰주고

 

"연결 씬" 이라고 적었던 Text 도 없애버리면

이렇게 볼 수 있음
버튼에다가 아까 만들었던 함수 넣은 모습


닉네임 InputFiled 관련 코드 및 InputField 에 어떤게 써져 있어야만 버튼이 활성화 되게 하자

 

변수 선언

닉네임을 인풋닉네임의 txt 로 해주자.

Assign 잘 해주고

이제 이름 쓰고 접속하면 그게 NickName 이 되게 됨!

 


값 안넣어주면 Button 안되게 하기

이게 체크되야 버튼 사용가능

 

InputField 에 있는 3가지

 

닉네임이 변할 때마다 호출하는 함수를 이렇게 하는거임
와 한줄로,,,,

Button Interactive 꺼놓고 시작하면 됨

 

각 메소드의 역할

 

Enter 누르면 접속 할 수 있게 해주는것