유니티 5강 - 이동 - 조이스틱 - svn - 오디오 스태틱으로 제어 - c# 기본 템플릿 설정


* CN Control 소스
http://freebox.myqnapcloud.com:8080/share.cgi?ssid=0ycrmf1
* 작업 소스 ( 9 - 7 )
http://freebox.myqnapcloud.com:8080/share.cgi?ssid=0ECeR9l
* apk
http://freebox.myqnapcloud.com:8080/share.cgi?ssid=0Bq0iDR

SVN 서버 연결법

네이버 개발자 센터 접속 -> 화면 오른쪽 하단 -> 오픈프로젝트 -> 새프로젝트 만들기
http://developer.naver.com/


















프로젝트 관리 -> 모두 비공개로.

코드 --> 나의 주소 확인 

오른쪽 상단 마이 페이지 -> 회원정보 -> 코드저장소 비밀번호 설정 -> 비밀번호 적용(프로젝트 비밀번호)

SVN 클라이언트(접속기) 다운

구글 검색 거북이SVN ( http://tortoisesvn.net/ ) -> 다운로드 -> 
64BIT 다운 (http://tortoisesvn.net/downloads.html) -> 프로그램 설치 -> 다음다음다음... 설치

폴서 우클릭-> 설치 된 화면 확인

유니티 메뉴 -> EDIT -> PROJECT SETTING -> EDITOR -> 인스펙터에서 -> 선택



* 빌드 -> 플레이어 셋팅
컴패니 네임 
프로덕트 네임 -> 아이콘 바로 아래 나오는 이름

사운드 추가 및 설정
 -> 압축 해제 설정(바로 나올 수 있게)





카메라 에 붙어 있는 오디로 리스너로 3d 사운드(거리 계산)을 적용한다.
오디오 리스너는 씬 안에서 절대 2개가 존재 할 수 없다.
카메라를 2개 생성 할 때에는 사용하지 않는 오디오 리스너는 삭제한다(리무브 컴포넌트).

오디오 출력을 위한 컴포넌트 -> 오디오 소스(스피커, 소리를 내는 컴포넌트로 생각)
오스오 소스 Pitch -> 음의 높 낮이


Character Controller 의 Step Offset 는 캐릭터가 올라갈(높이) 수 있는 범위.
(예를 들어 계단 올라갈 수 있는 범위를 지정 할 수 있음.)

시작 템플릿 설정. 위 사진 폴더의 파일 열어서 템플릿을 설정한다.



조이스틱 붙이기!!




유니티 에셋 스토어 CN - Control 검색후 설치


CNJoystickMovement  = 움직임을 담당
게임 씬
CNJoystickMovement 복사 후 NGUI 카메라의 자식으로 붙임.(혹은 메인카메라)



레이어 ngui로 설정


CN Joystick 스크립트 -> 터치존 사이즈 ( 실제 터치 되는 사이즈 )
마진 -> 좌우 상하 위치 이동
드래그 래디우스 -> 드래그가 되는 크기
스냅 투 핑거스 화면 영역 전체에서 조이스틱이 나타난다.
크기는 트랜스폼으로 설정


pc와 모바일 상태에 따른 조이스틱 설정하기
플랫폼별 상태 체크

구글검색 unity define
http://docs.unity3d.com/kr/current/Manual/PlatformDependentCompilation.html// 플랫폼별 상태 설정

// 플랫폼별 상태 설정 #을 앞에 붙임
#if UNITY_EDITOR // 유니티 에디터 상태일때
 
        float dirX = Input.GetAxis("Horizontal");
        float dirY = Input.GetAxis("Vertical");
#else // 에디터가 아닌상태 (모바일)
        //조이스틱 코드
        float dirX = stick.GetAxis("Horizontal");
        float dirY = stick.GetAxis("Vertical");
#endif // 상태 끝




====[  MouseLook  ]========================
using UnityEngine;
using System.Collections;
 
public class MouseLook : MonoBehaviour 
{
 
    public float _speed = 100;
 
    float rotationX = 0;
    float rotationY = 0;
 
    //PlayerState 스크립트 파일 확인
    PlayerState playerStat;
 
    public CNJoystick cnJoySk;
 
    void Start()
    {
        // 트랜스폼이 상속받은 자식 플레이어이기 때문에 부모 게임오브젝트를 참조 할 수 있다.
        GameObject playObj = this.transform.parent.gameObject;
        playerStat = playObj.GetComponent<PlayerState>();
      
        
    }
 
    void Update () 
    {
 
    
        // 플레이어 사망 확인
        if(playerStat.Dead == truereturn;
        
        // 이동공식
        //dir * speed * time
        //방향 * 속도 * 시간 
        // 마우스의 X이동값을 입력받음
        // 방향은 -1 ~ 1 사이에서 사용
#if UNITY_EDITOR        
        float dirX = Input.GetAxis("Mouse X");
        float dirY = Input.GetAxis("Mouse Y");
        // 조이스틱 이용
#else
        float dirX = cnJoySk.GetAxis("Horizontal");
        float dirY = cnJoySk.GetAxis("Vertical");
#endif
        // 마우스의 회전값을 가지고 있는 변수
        // X축은 그대로 두고 있어야 하기 때문에 dirY을 대입
        rotationX += dirY * _speed * Time.deltaTime;
        rotationY += dirX * _speed * Time.deltaTime;
 
        // 마우스의 움직임에 따라 이동하는 회전각을 고정
        if (rotationX > 90) rotationX = 90;
        if (rotationX < -90) rotationX = -90;
 
        //회전값을 사용하면 반드시 eulerAngles (오일러앵글스) 를 사용한다.
        transform.eulerAngles = new Vector3(-rotationX, rotationY, 0);
    }
}

====[  PlayerMove ]========================
using UnityEngine;
using System.Collections;
 
public class PlayerMove : MonoBehaviour {
 
    public float speed = 5;
 
    public CNJoystick stick = null;
    
    // 초기화 주소값을 가진다 = null;
    CharacterController chraCtr = null;
 
    PlayerState playerSteate = null;
 
    void Start () 
    {
        playerSteate = GetComponent<PlayerState>();
        //chraCtr은 GetComponent의 CharacterController을 참조한다.
        // CharacterController 타입을 찾아서 넘겨준다.
        chraCtr = GetComponent<CharacterController>();
    }
    
    
    void Update () 
    {
        if (playerSteate.Dead == truereturn;
 
        
        
        
        // 캐릭터 컨트롤러의 Move() 메서드를 실행
        // dir * speed * time
        // 아래 코드는 조이스틱이 없을때 사용 
// 플랫폼별 상태 설정 #을 앞에 붙임
#if UNITY_EDITOR // 유니티 에디터 상태일때
 
        float dirX = Input.GetAxis("Horizontal");
        float dirY = Input.GetAxis("Vertical");
 
#elif UNITY_WEBPLAYER  //#elif = else if로 사용한다
        float dirX = Input.GetAxis("Horizontal");
        float dirY = Input.GetAxis("Vertical");
 
#else // 에디터가 아닌상태 (모바일)
        //조이스틱 코드
        float dirX = stick.GetAxis("Horizontal");
        float dirY = stick.GetAxis("Vertical");
#endif // 상태 끝
 
        // 뎁스로 이동해야 하기때문에 z값에 Vertical키의 값을 입력 해준다.
        // Vector3는 3가지 값을 가지기 때문에 앞뒤 전후 좌우 값을 입력 해 줄 수 있다.
        Vector3 dir = new Vector3(dirX, 0, dirY); //dirX 좌우값  dirY 앞뒤값
        
        //180도 돌았을때의 문제 해결
        // 메인카메라 main은 스태틱 언제든지 불러 올 수 있음. 스태틱 변수는 new 가 안됨
        //카메라 게임오브젝트를 기준으로 방향을 설정한다(왼쪽이냐 오른쪽이냐 판별함)
        //dir변수에 카메라 디렉션을 대입한다.
        dir = Camera.main.transform.TransformDirection(dir);
        dir.y = 0;
        chraCtr.Move(dir * speed * Time.deltaTime); 
       
 
    }
 
}

====[  PlayerState ]========================

using UnityEngine;
using System.Collections;
 
public class PlayerState : MonoBehaviour
{
    //50/100 = 0.5
    // 최대 체력
    const float hpMax = 100;
    public int hp = 100;
    // 캐릭터 사망 확인 불 변수.
    bool isDead = false;
    //정지 상태
    bool isPause = false;
 
    public void Pause()
    {
        //! 는 반전연산자 ( false = true로 바꿔주고 true는 false로 바꿔준다)
 
        isPause = !isPause;
 
        if (isPause == true)
        {
            // 타임 스케일을 사용해도 업데이트 함수는 돌아간다.
            Time.timeScale = 0;
        }
        else
        {
            Time.timeScale = 1;
        }
    }
 
    //isPause 상태에 대한 프로퍼티 생성(읽기전용)
    public bool iPause
    {
        get
        {
            return isPause;
        }
    }
 
    // isDead에 대한 프로퍼티 생성. ( 읽기전용 )
    public bool Dead
    {
        get
        {
            return isDead;
        }
    }
 
 
    public UISlider hpSlider;
 
    public GameObject PopUp;
 
 
 
    void Start()
    {
 
 
    }
 
 
    void Update()
    {
 
    }
 
    public void damage()
    {
 
        if (isDead) return//_hp 가 -값으로 내려가지 않도록.
        hp -= 5;
        // 비율 계산
        float ratio = (float)hp / hpMax;
        hpSlider.value = ratio;
        if (hp <= 0)
        {
            isDead = true;
            Die();
        }
 
 
        print("현재 체력은 : " + hp);
 
    }
 
    public void Die()
    {
        // 팝업창 띄움
        PopUp.SetActive(true);
        print("죽었어....");
 
    } 
}

====[  Spider ]========================
using UnityEngine;
using System.Collections;
 
public class Spider : MonoBehaviour
{
 
    //델리게이트 선언
    delegate void State();
 
 
 
    // enum 코드의 효율성을 주고 싶을때. 문자로 표시 할 수 있음 가독성을 높일 수 있음.
    public enum SpiderState
    {
        // 첫번째 변수에 0을 대입하면 순차적으로 Move = 1, Attack = 2, Damage = 3 순으로 올라간다
        None = -1,// 생성되어 있지 않고 아무것도 아닌 대기상태
        Idle,
        Move,
        Attack,
        Damage,
        Dead,
        Max
    }
 
    //델리게이트 형 배열 선언
    //(int)SpiderState.Max = enum 의 마지막.(int(숫자))형으로 변환
    //배열을 맴버변수로 선언할때 메소드 위에 선언하면 메소드의 주소를 찾을 수 없다.
    State[] funState = null;
 
    // 플레이어 데미지
    PlayerState playerDamage;
 
    // 애니메이션 컴포넌트 참조 할 변수
    Animation monAni = null;
    GameObject target = null;
 
    //대기 시간 변수
    float interVal = 0;
    //const 를 선언하면 값을 변할 수 없게 한다.
    const float attackRange = 3; //공격범위
    const float attackTime = 2;  //공격시간
 
    int hp = 5;
 
    // enum 참조
    // enum SpiderState를 변수 state에 대입    
    // 무브를 실행 하려면 = SpiderState state = SpiderState.Move;
 
    SpiderState state = SpiderState.Idle;
 
    //상태처리 함수 생성   
    void Idle() // 대기
    {
 
        // monAni.Play("idle");
 
        //타이머 설정 
        interVal += Time.deltaTime; //interVal변수에 현재 시간의 흐름(float)을 더해준다.
        if (interVal > attackRange) //2초 지난뒤 실행
        {
            //2초 지난뒤 SpiderState.Move 호출
            state = SpiderState.Move;
            interVal = 0; // 재활용을 위해 초기화 시킨다
        }
    }
 
    void Move()
    {
        // 거리값 계간 함수 Vector3.Distance(a의 위치 , b의 위치);
        float distance = Vector3.Distance(target.transform.position, this.transform.position);
        //거리값으로 공격 호출       
        if (distance < attackRange)
        {
            state = SpiderState.Attack;
            // 인터벌 어택타임 3초로 대입하여 플레이어와 가까워 졌을때 바로 공격
            interVal = attackRange;
 
        }
 
        else
        {
            // 이동
            // 타겟 - 자기 자신 ( 방향 설정 ) * 이동 공식 외울것.
            // dir에 플레이어의 위지를 대입하고 자기 자신의 위치값을 뺀다.
            Vector3 dir = target.transform.position - this.transform.position;
            //normalized = ??? 벡터를 만들기 위해 실행 한 함수.
            dir.Normalize();
            dir.y = 0;
            //이동 코드 = 자기 자신의 위치 += 이동방향 * 속도 * 시간
            this.transform.position += dir * 5 * Time.deltaTime;
 
            // 플레이어의 회전 방향 대입
            Quaternion to = Quaternion.LookRotation(dir);
            // 회전  Lerp() = 시간에 따라 부드러운 처리 사용
            // Quaternion.Lerp(자기자신의 회전 방향(값), 바라보고 싶은 방향(값 플레이어),시간(회전할 시간 각) );
            // 10 * Time.deltaTime 매 프레임마다 각을 계산
            //this.transform.rotation = Quaternion.Lerp(this.transform.rotation,to, 10 * Time.deltaTime);
            this.transform.rotation = Quaternion.Lerp(this.transform.rotation, to, 0.05f);
 
            monAni.Play("walk"); // 이동 애니메이션 호출
        }
 
 
 
 
    }
 
    void Attack() // 공격
    {
 
        interVal += Time.deltaTime;
        // 2초에 한번 공격
        if (interVal > attackTime)
        {
            // 플레이어 damage  메서드 호출
            playerDamage.damage();
 
            monAni.Play("attack"); // 공격 애메니이션 호출
            // PlayQueued : attack(이전 attack은 루프가 되면 안됨) 애니메이션 뒤에 idle 애니메이션을 추가 함.
            monAni.PlayQueued("idle");
 
            interVal = 0;
        }
 
        //플레이어와 거리가 멀어지면 다시 idel 호출
        if (Vector3.Distance(target.transform.position, this.transform.position) > attackRange)
        {
            state = SpiderState.Idle;
            interVal = 0;
        }
 
 
    }
 
    void Damage() // 데미지
    {
        monAni.Play("damage");
        monAni.PlayQueued("idle");
 
        interVal = 0;
        state = SpiderState.Idle;
        hp--;
        if (hp <= 0)
        {
            state = SpiderState.Dead;
        }
 
    }
    void Dead() // 죽음
    {
 
        state = SpiderState.None; // 코루틴 작동 안됨
        StartCoroutine(DeadProcess()); // 
        //Destroy(this.gameObject, 0.5f);
 
 
    }
 
    void Reset()
    {
        hp = 5;
        state = SpiderState.Idle;
        monAni.Play("idle");
    }
 
    //public AnimationClip[] clip = null;
 
 
    IEnumerator DeadProcess()
    {
        // 죽음 사운드 
        AudioMag.audioMrg.PlaySfx(AudioType.Death);
 
        monAni.Play("death");
 
        //애니메이션 시간 구하기(레거시용)
        float length = monAni["death"].length;
        yield return new WaitForSeconds(length + 1); // 애니메이션 시간 + 1초 
 
        // 몬스터 사망시 아래로 내려가는 코드
        while (this.transform.position.y > -2)
        {
            Vector3 temp = this.transform.position;
            //this.transform.position.y = .y로 바로 접근 할 수 없음.
            temp.y -= 0.5f * Time.deltaTime;// 매프레임마다 0.5f만큼 뺀다
            this.transform.position = temp;
 
            // 코루틴 대기 ,일정 프레임에 한번씩 대기 동시 작업 가능
            // 코루틴에서 while문을 사용 할 때 사용
            yield return new WaitForEndOfFrame();
        }
 
 
        Reset();
        this.gameObject.SetActive(false);
 
 
    }
 
 
 
 
    void OnCollisionEnter(Collision col)
    {
 
        if (state == SpiderState.None || state == SpiderState.Dead) return;
        // 레이어 인덱스는 문자로 넣어도 숫자로 반환된다.
        // 레이어 인덱스는 int형 변수에 대입된다
        int layerIndex = col.gameObject.layer;
        //레이어 마스크로 부딪히는 오브젝트 이름 가져옴
        if (layerIndex == LayerMask.NameToLayer("ball"))
        {
            state = SpiderState.Damage;
        }
 
        /*
        if (col.gameObject.tag == "bullet")
        {
            state = SpiderState.Damage;
 
        }
        */
    }
 
 
    void Start()
    {
        // 델리게이트 배열 대입 한줄로 선언.   
        funState = new State[(int)SpiderState.Max] { Idle, Move, Attack, Damage, Dead };
 
        // 델리게이트 배열에 각 메소드 대입 초기화        
        /*
        funState[(int)SpiderState.Idle] = Idle;
        funState[(int)SpiderState.Move] = Move;
        funState[(int)SpiderState.Attack] = Attack;
        funState[(int)SpiderState.Damage] = Damage;
        funState[(int)SpiderState.Dead] = Dead;
        */
 
        // 매카닉(new) 애니메이션 방식은 Animator 레거시(old) 방식은 Animation
        // 몬스터 애니메이션에서 idle 애니메이션을 플레이 시킨다. 레거시 방식은 초기 루프가 기본이 아니다.
        monAni = GetComponent<Animation>();
        // 태그로 플레이어 검색
        target = GameObject.FindGameObjectWithTag("myPlayer");
        playerDamage = target.GetComponent<PlayerState>();
 
 
 
    }
 
 
    void Update()
    {
        // enum 의 메소드 호출 방법 delegate사용
        if (state == SpiderState.None) return;
        funState[(int)state]();
 
 
        // enum 의 메소드 호출 방법 swich사용
        /*
        switch (state)
        {
            case SpiderState.Idle:
                {
                    Idle();
                }
                break;
            case SpiderState.Move:
                {
                    Move();
                }
                break;
            case SpiderState.Attack:
                {
                    Attack();
                }
                break;
            case SpiderState.Damage:
                {
                    Damage();
                }
                break;
            case SpiderState.Dead:
                {
                    Dead();
                }
                break;
 
        }
         */
 
    }
}









댓글

이 블로그의 인기 게시물

날짜 시간 시간차 시간 계산 하기

코루틴에서 CallBack 함수 적용하기

C++ 언어 퍼센트 구하는 방법 / 기본 언어 퍼센트 구하는 방법