* 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 == true) return;
// 이동공식
//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 == true) return;
// 캐릭터 컨트롤러의 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;
}
*/
}
}
댓글
댓글 쓰기