배운 것들

닷지 게임 클론코딩

이번 주 첫 수업에는 닷지 게임을 클론코딩 하는 시간이 있었다.

조이스틱

위 사진은 조이스틱인데 rect transform 개념도 그렇고 절대적 상대적 위치에 대한 개념에서 많이 헷갈렸던 것 같다.

Input.OnDrag에서 받은 값에서 background 좌표를 뺸 벡터(이동한 벡터 값)에서 background 반지름에서 handler 반지름을 뺀 벡터(파란 부분)로 나누어주어 비율을 계산하고 최대 크기를 1로 고정하여 이를 handle의 position으로 적용시켜준 것이다.

 

위치기반서비스(LBS) 게임

mapbox에서 써드 파티로 플러그인을 가져오는 LBS 게임에 대해서도 배웠다.

LBS 게임

https://www.mapbox.com/

 

Maps, geocoding, and navigation APIs & SDKs | Mapbox

Integrate custom live maps, location search, and turn-by-turn navigation into any mobile or web app with Mapbox APIs & SDKs. Get started for free.

www.mapbox.com

mapbox 사이트에서 맵을 가져올 수 있는데 맵에 커스텀 스킨을 입히거나 좌표를 변경하거나 해서 가져올 수도 있다. 나중에는 AR 게임에 대해서도 배운다는데 기대가 된다.

 

 

과제 내용

- Velocity over Lifetime으로 시간에 따른 원 크기, 각도 조절

- Emission과 maxParticles로 파티클 갯수 조절

- Color over Lifetime으로 시간에 따른 색 바꾸기

- Size over Lifetime으로 시간에 따른 크기 조절

파티클

 

 

한 주 후기

 이번 주는 닷지 토이프로젝트를 클론코딩하는 시간을 가졌다. 닷지 게임 자체가 되게 단순하고 만들기 어렵지 않을 것이라 생각했지만 rect transform의 앵커, 피벗 부분이나 Canvas와 Canvas 밖의 스프라이트(플레이어, 총알)가 다른 좌표를 사용하는 게 어려웠다. 조이스틱을 구현하는데 그냥 transform.position과  transform.anchoredPosition의 차이가 이해하는데 꽤 걸렸다. 간단한 닷지 프로젝트 하나에도 여러가지 구현들이 적용되는구나 하고 느꼈다.

클론코딩을 하면서 내가 구현한 방식은 이거였는데 이런 식으로 구현하면 더 효율적으로 구현할 수 있구나 (ex : 반환형 함수를 사용해서 전달하여 굳이 전역 변수를 선언하지 않아도 되는 경우 등) 라는 걸 많이 배운 것 같다. 나중엔 매개변수와 반환형 함수를 적절히 사용하여 굳이 불필요한 메모리 낭비나 종속성을 피하는 방향으로 가야겠다고 생각했다.

 이번 주에는 비가 너무 많이와서 정신 없었지만 그래도 한 주 동안 많은 것을 배웠다. 이후로도 배운 것을 복습하면서 내재화시키는 노력을 해야겠다. 다음주도 파이팅!

 

유데미코리아 바로가기

본 포스팅은 유데미-웅진씽크빅 취업 부트캠프 유니티 1기 과정 후기로 작성되었습니다.

Invoke

Invoke 사용하기

- 메서드가 x초 동안 지연된 이후 실행되게 할 수 있음

- 문법 : Invoke("함수 이름", 지연시간);

- 장점 : 사용하고 이해하기 쉬움

- 단점 : 문자열 참조로 함수 이름을 변경하거나 동적으로 할당할 때 불편함, 코루틴에 비해 성능이 떨어짐

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

public class CollisionHandler : MonoBehaviour
{
    [SerializeField]
    float levelLoadDelay = 1f;
    private void OnCollisionEnter(Collision collision)
    {
        switch (collision.gameObject.tag)
        {
            case "Friendly":
                Debug.Log("This thing is firendly");
                break;
            case "Finish":
                StartSuccessSequence();
                break;
            default:
                StartCrashSequence();
                break;
        }
    }

    // 추락 시퀀스 후 씬 전환
    void StartCrashSequence()
    {
        // 추락할 때 효과음 넣기
        // 추락할 때 파티클 넣기
        GetComponent<Movement>().enabled = false;
        Invoke("ReLoadLevel", levelLoadDelay);
    }

    void LoadNextLevel()
    {
        int currentSceneIndex = SceneManager.GetActiveScene().buildIndex;
        int nextSceneIndex = currentSceneIndex + 1;
        // SceneManager.sceneCountInBuildSettings 인덱스 총 갯수를 계산
        if (nextSceneIndex == SceneManager.sceneCountInBuildSettings)
        {
            nextSceneIndex = 0;
        }
        SceneManager.LoadScene(nextSceneIndex);
    }

    // 성공 시퀀스 후 씬 전환
    void StartSuccessSequence()
    {
        // 추락할 때 효과음 넣기
        // 추락할 때 파티클 넣기
        GetComponent<Movement>().enabled = false;
        Invoke("LoadNextLevel", levelLoadDelay);
    }

    void ReLoadLevel()
    {
        // 변수에 저장하는 이유는 나중에 봤을 때 코드를 해석할 시간을 줄이기 위해서이다.
        int currentSceneIndex = SceneManager.GetActiveScene().buildIndex;
        // 현재 실행되고 있는 씬의 인덱스를 불러옴
        SceneManager.LoadScene(currentSceneIndex);
    }
}

도착 했을 때
부딪쳤을 때

 

함수명이 하는 기능을 나타내주도록 구분하는 게 중요한 것 같다

ex) StartCrashSequence는 충돌시 시퀀스에 관한 부분

ReloadLevel은 씬 재시작에 관한 부분

'유데미 강의 > C#과 Unity로 3D 게임 개발하기 : 부스트 프로젝트' 카테고리의 다른 글

bool 변수로 제어하기, 로켓 꾸미기  (0) 2022.08.23
오디오 클립  (0) 2022.08.23
SceneManager  (0) 2022.08.12
Switch  (0) 2022.08.12
유니티 오디오  (0) 2022.08.12

SceneManager

Scene들의 이동은 Build Settings의 Scenes In Build 내의 씬들을 기반으로 이동한다.

* File - Build Settings로 접근 가능하다.

- 씬은 Add Open Scenes를 눌러 현재 켜져있는 씬을 추가하거나 드래그 앤 드롭으로 에셋폴더에 있는 씬을 Scenes In Build에 가져다 넣어서 추가하면 된다.

- 우측에 숫자는 인덱스인데 0부터 시작한다. (배열의 인덱스와 비슷)

Build Settings

 

CollisionHandler.cs

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

public class CollisionHandler : MonoBehaviour
{
    private void OnCollisionEnter(Collision collision)
    {
        switch (collision.gameObject.tag)
        {
            case "Friendly":
                Debug.Log("This thing is firendly");
                break;
            case "Finish":
                Debug.Log("Congrats, yo, you finished!");
                LoadNextLevel();
                break;
            case "Fuel":
                Debug.Log("You picked up fuel");
                break;
            default:
                Debug.Log("Sorry, you blew up!");
                ReLoadLevel();
                break;
        }
    }

    void LoadNextLevel()
    {
        int currentSceneIndex = SceneManager.GetActiveScene().buildIndex;
        int nextSceneIndex = currentSceneIndex + 1;
        // SceneManager.sceneCountInBuildSettings 인덱스 총 갯수를 계산
        if (nextSceneIndex == SceneManager.sceneCountInBuildSettings)
        {
            nextSceneIndex = 0;
        }
        SceneManager.LoadScene(nextSceneIndex);
    }

    void ReLoadLevel()
    {
        // 변수에 저장하는 이유는 나중에 봤을 때 코드를 해석할 시간을 줄이기 위해서이다.
        int currentSceneIndex = SceneManager.GetActiveScene().buildIndex;
        // 현재 실행되고 있는 씬의 인덱스를 불러옴
        SceneManager.LoadScene(currentSceneIndex);
    }
}

 

정상적으로 다음 씬으로 넘어가고

마지막 레벨에 다다랐을 때 첫 씬으로 돌아오는 것을 확인할 수 있다.

'유데미 강의 > C#과 Unity로 3D 게임 개발하기 : 부스트 프로젝트' 카테고리의 다른 글

오디오 클립  (0) 2022.08.23
Invoke 함수 사용  (0) 2022.08.12
Switch  (0) 2022.08.12
유니티 오디오  (0) 2022.08.12
소스 컨트롤  (0) 2022.08.12

Switch문

If나 Else문 같은 조건문으로 하나의 변수와 비교하여 참인 경우만 해당라인 코드를 실행한다.

Switch 문법

switch (비교할 변수)
        {
        	// 비교할 변수와 case 뒤의 변수가 같을 때 아래 코드를 실행
            // break;를 만나면 switch문 탈출
            // default는 다른 case들이 변수와 일치하지 않을 때 실행
            case valueA:
                메서드A();
                break;
            case valueB:
                메서드B();
            default:
                메서드C();
                break;
        }

 

CollisionHandler.cs

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

public class CollisionHandler : MonoBehaviour
{
    private void OnCollisionEnter(Collision collision)
    {
        switch (collision.gameObject.tag)
        {
            case "Friendly":
                Debug.Log("This thing is firendly");
                break;
            case "Finish":
                Debug.Log("Congrats, yo, you finished!");
                break;
            case "Fuel":
                Debug.Log("You picked up fuel");
                break;
            default:
                Debug.Log("Sorry, you blew up!");
                break;
        }
    }
}

플레이

Collision Switch문

'유데미 강의 > C#과 Unity로 3D 게임 개발하기 : 부스트 프로젝트' 카테고리의 다른 글

Invoke 함수 사용  (0) 2022.08.12
SceneManager  (0) 2022.08.12
유니티 오디오  (0) 2022.08.12
소스 컨트롤  (0) 2022.08.12
오브젝트 회전과 매개변수와 Rigidbody  (0) 2022.08.04

유니티 오디오

효과음을 내기위한 세 가지

Audio Listener

- 오디오를 듣기

Audio Source

- 오디오를 플레이 하기

Audio File

- 재생되는 소리

 

Audio Listener

메인 카메라에는 기본적으로 Audio Listener가 들어있는데 기본 설정상 우리가 보는 화면이기 때문이다.

메인 카메라 오디오 리스너

오디오 소스나 오디오 리스너는 다른 컴포넌트처럼 오브젝트에 추가해서 사용한다.

오디오 소스

Audio Source

오디오 소스 컴포넌트는 오디오 클립을 추가해서 플레이 하는 식으로 동작한다.

- Play On Awake : 시작할 때 켜짐

- Loop : 반복

오디오 소스 2

 

Audio File

- 오디오 파일 다운로드 사이트 (저작권 주의)
https://freesound.org/

 

Freesound - Freesound

Freesound Blog Recent Additions Woodpecker pecking on a tree, slight wind shaking foliage, birds singing, far plane passing and road hum at the end ... 13 more sounds from felix.blume in the last 48 hours 4 more sounds from josefpres in the last 48 hours 2

freesound.org

- 직접 효과음 녹음하는 사이트

https://www.audacityteam.org/

 

Home

Welcome to Audacity Audacity® is free, open source, cross-platform audio software for multi-track recording and editing. Audacity is available for Windows®, Mac®, GNU/Linux® and other operating systems. Check our feature list, Wiki and Forum. Download

www.audacityteam.org

 

오디오 파일은 이런식으로 에셋 폴더에 넣고 누르면 확인이 된다.

오디오 파일을 Audio Source 컴포넌트의 Audio Clip에 드래그 앤 드롭다운 해서 넣으면 플레이할 준비가 된 것이다

오디오 클립


Movement.cs

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

public class Movement : MonoBehaviour
{
    private Rigidbody rigid;
    private AudioSource audioSource;
    [SerializeField]
    private float mod = 100f;
    [SerializeField]
    private float rotationSpeed = 1f;
    void Start()
    {
        rigid = GetComponent<Rigidbody>();
        audioSource = GetComponent<AudioSource>();
    }

    void Update()
    {
        ProcessThrust();
        ProcessRotation();
    }

    void ProcessThrust()
    {
        if (Input.GetKey(KeyCode.Space))
        {
            rigid.AddRelativeForce(Vector3.up * mod * Time.deltaTime); // Time.deltaTime은 1프레임당 시간
            // 재생하고 있지 않을 때만 재생 (재생이 겹치는 걸 막음)
            if (!audioSource.isPlaying)
                audioSource.Play();
        }
        else
            audioSource.Stop();
    }

    void ProcessRotation()
    {
        if (Input.GetKey(KeyCode.A))
        {
            // Ctrl + .으로 반복되는 문장을 함수로 빠르게 만들 수 있다.
            // 반복되는 문장은 다른 것만 매개변수로 받으면 좋다.
            // Ctrl + R 두 번으로 이름을 한 번에 수정할 수 있다.
            ApplyRotation(rotationSpeed);
        }
        else if (Input.GetKey(KeyCode.D))
        {
            ApplyRotation(-rotationSpeed);
        }
    }

    private void ApplyRotation(float rotationThisFrame)
    {
        // 비트연산이라 더하면 xy 값 물리적 고정과 같음
        // rigid.constraints = (RigidbodyConstraints)((int)RigidbodyConstraints.FreezeRotationX + (int)RigidbodyConstraints.FreezeRotationY);
        // 물리적으로 회전 고정
        // rigid.constraints = RigidbodyConstraints.FreezeRotation;
        
        rigid.freezeRotation = true; // 회전 값을 고정해서 수동으로 회전을 조작할 수 있게 함
        // 이게 되는 이유는 rigid(물리)충돌의 회전만 제어했을 뿐이지 transform 기반으로 한 회전은 수동으로 제어 가능 
        transform.Rotate(Vector3.forward * rotationThisFrame * Time.deltaTime);
        rigid.freezeRotation = false; // 회전 값 고정을 풀어서 물리 시스템이 적용 됨
    }
}

'유데미 강의 > C#과 Unity로 3D 게임 개발하기 : 부스트 프로젝트' 카테고리의 다른 글

SceneManager  (0) 2022.08.12
Switch  (0) 2022.08.12
소스 컨트롤  (0) 2022.08.12
오브젝트 회전과 매개변수와 Rigidbody  (0) 2022.08.04
부스터  (0) 2022.08.03

소스 컨트롤

코드 및 프로젝트의 변경 사항을 추적 및 관리하는 시스템 

- 무엇이 변경됐는지 알 수 있는 좋은 방법

- 변경하려던 것이 잘 풀리지 않거나 변경하기 싫었던 것을 변경했을 때 이전 버전으로 돌아갈 수 있음

ex) Git, Gitlab, Github

Gitlab : 호스팅 서비스를 할 수 있는 저장소(온라인 공간)

Repository - 프로젝트를 공개적으로 호스팅하면 무료로 여러 버전을 사용할 수 있고 온라인에서 클라우드로 프로젝트를 호스팅 할 수 있다. (우리가 프로젝트를 저장하는 공간) 

SourceTree : 리포를 볼 수 있도록 돕는 데스크톱 클라이언트

 

소스 컨트롤을 사용하는 이유

- 프로젝트를 저장하기 좋은 방법이다 => 하드드라이브에 문제가 생겨도 안전하게 보호되도록 클라우드에 저장하는 것

- 돌아갈 수 있는 프로젝트의 이전 버전이 있다는 것을 알면 프로젝트를 안전히 변경할 수 있음

- 동시에 여러 아이디어를 한 번에 적용할 수도 있음(여러 아이디어 실험)

- 다른 작업자들과 쉽게 공유할 수 있음

* 아래처럼 뭐가 추가가 됐고 뭐가 빠졌는지 알 수 있다. (좌측 빨간색 빠진 것, 우측 초록색 추가된 것)  

깃 데스크탑

 히스토리를 클릭하면 이 특정 파일의 히스토리를 보여준다.

히스토리

깃허브의 코드를 누르면 클론을 만들어서 로컬 저장소에 저장할 수 있다.

클론

'유데미 강의 > C#과 Unity로 3D 게임 개발하기 : 부스트 프로젝트' 카테고리의 다른 글

Switch  (0) 2022.08.12
유니티 오디오  (0) 2022.08.12
오브젝트 회전과 매개변수와 Rigidbody  (0) 2022.08.04
부스터  (0) 2022.08.03
클래스, Input 클래스  (0) 2022.08.03

배운 것들

애니메이션

프레임의 집합이다.

- 오브젝트 클릭 후 Window- animation - animation에서 애니메이션을 생성할 수 있다.

- 더블클릭하면 키 프레임가 생성됨

- 녹화버튼 누르고 씬에서 수정시 키프레임이 생성됨

- 기본은 Dopesheet

Animation

아래의 Dopesheet 대신 Curves를 선택하면 사진처럼 프레임의 높이를 조절해 연결을 부드럽게도 만들 수 있다.

Curves

애니메이션 이벤트

애니메이션의 작대기 버튼의 이벤트를 프레임에 생성하여 해당 오브젝트 안의 함수를 실행할 수도 있다.

애니메이션 Event

 

애니메이터

애니메이터는 실제 오브젝트에 추가되는 조건에 따른 애니메이션을 보여주는 컴포넌트다.

- 조건 변수인 Parameters가 있음

- Transition으로 조건을 설정 가능함

- 한 애니메이션에서 화살표(Transition)로 연결된 다른 애니메이션으로만 접근 가능함

- Any State에 연결된 애니메이션은 조건 충족시 Entry에 실행과 상관 없이 실행됨

Animator

애니메이터 레이어

추가 레이어를 사용하여 기존 애니메이션을 덮어 쓰거나 다른 애니메이션과 가중치를 정해 섞는다던가 할 수 있다.

ex) 뛰는 애니메이션이 있고 공격 버튼을 눌렀을 때 팔만 공격 모션으로 덮어쓰고 싶은 경우

Animator Layer

 

트랜지션

애니메이터의 화살표 부분으로 조건에 따른 실행 여부나 다음 애니메이션으로의 연결을 다룬다.

- Condition은 화살표 끝방향 애니메이션의 실행 조건임

- Has Exit Time 조절으로 다음 애니메이션이 부드럽게 이어지거나 현 애니메이션이 다 끝난 후 다음 애니메이션이 실행되는 등을 정할 수 있다.

Transition

 

코드에서 애니메이터 다루기

Animator로 접근하여 코드에서 애니메이션 파라미터 값을 바꿀 수도 있다.

코드로 접근하기

 

 

포스트 프로세싱

카메라의 필터처럼 보는 화면에 효과를 부여하는 기술이다.

- 패키지 매니저에서 설치가 가능하다.

Post Processing

Post-process Layer

어떤 것만 선택해서 효과를 보여줄 지, 어떤 걸 트리거로 설정해서 포스트 프로세싱을 적용할지를 결정하는 컴포넌트이다. 

Post-process Layer

Post-process Volume

생성한 Profile을 기준으로 어떤효과를 줄 지 정할 수 있다.

- Is Global을 체크하여 월드에 효과를 줄 지 아니면 범위로만 효과를 줄 지 정할 수 있음

- Blend Distance로 거리에 따라 서서히 효과를 줄 수 있음

- Weight로 효과에 대한 전체적인 값을 조정이 가능함

- Priority로 우선 적용 값을 넣을 수 있음

Post-process Volume

 

파티클

Particle System이라는 컴포넌트로 오브젝트에 파티클 효과를 부여할 수 있다.

- 모양, 주기, 속도, 갯수 등등 여러가지를 정할 수 있음

파티클

 

 

과제 내용

내 캐릭터를 선택한 후 적이 피를 전부 잃을 때까지 각도와 힘을 조절하여 포탄을 쏘는 게임이다.

- UI와 Sprite로 제작하여 World Space 공간에서 UI와 게임 화면을 구분해 제작

- 각도와 파워가 적용된 총알 발사

- 좀비 위의 hp UI가 다 줄었을 때 씬 재시작

Tank UI

 

 

한 주 후기

 이번 주에는 애니메이션, 애니메이터, 포스트 프로세싱, 파티클에 대해서 배웠다. 내가 직접 애니메이션의 키프레임을 찍어서 애니메이션을 만들어 보기도 하고 그 애니메이션을 여러개 만들어서 애니메이터에서 조건에 따라 실행해 보기도 하고 마지막으로 코드에서 이를 조작하는 것까지 할 수 있게 되었다. 또 포스트 프로세싱을 적용하여 공포게임 같은 연출을 보여줄 수도 있고 파티클로 눈이 내리는 연출 같은 것을 만들 수 있다는 걸 알게 되었다.

 이번 주 과제를 만들면서 UI 카메라와 게임화면 카메라를 구분하여 두는 것이 제일 어려웠는데 '카메라가 왜 두 개나 필요하지?' 라는 의문과 '그렇다면 어떤 방법으로 그 화면들을 구분하지?' 하는 의문이 해결되지 않았었다. 결국엔 이것 저것 건드려보다가 답을 찾았는데 첫 번째 카메라는 Culling Mask를 UI만 체크하여 UI 요소들만 찍게 하고 Depth only를 사용하여 다른 배경들은 투명하게 만든 다음, 두 번째 카메라는 Culling Mask를 UI를 제외한 나머지 요소들을 체크하면 첫 번째 카메라는 UI 카메라로 게임 진행 중에 게임 화면 위에 떠 있어야 하는 파워 게이지 같은 요소들을 보여주고 두 번째 카메라는 게임 카메라로 총알을 따라다니고 다른 오브젝트들을 비춰주게 함으로써 둘의 사용이 구분될 수 있었다.

 이번 주의 과제도 배운 내용을 가지고 잘 적용할 수 있는 시간이 되었으면 좋겠다. 포스트 프로세싱이나 애니메이션, 파티클 시스템 모두 눈으로 보이는 재미있는 효과들을 다루기 때문에 과제를 제작하는 시간이 즐거울 것이라 예상하고 있다. 또한 이번 주 수업은 미니 프로젝트들을 만들어 보는 것인데 추가적으로 질문할 거리도 많고 '이런식으로 만들어지는 거였어?' 하는 생각이 드는 등 수업도 기대가 된다.

 다음 주도 꾸준하게 이해가 될 때까지 질문하고 고민하여 완벽히 습득하는 시간이 됐으면 좋겠다. 다음 주도 파이팅!

 

 

유데미코리아 바로가기

본 포스팅은 유데미-웅진씽크빅 취업 부트캠프 유니티 1기 과정 후기로 작성되었습니다.

Transform.Rotation(Vector3 vec)

transform을 기준으로 vec만큼 회전한다.

매개변수

반복되는 문장은 다른 부분만 매개변수로 대입하는 함수를 만들어주면 실수도 방지할 수 있고 가독성이 올라간다.

- 호출할 때 함수의 인자는 선언한 함수의 매개변수 타입과 같아야한다.

* Ctrl + .으로 반복되는 문장을 함수로 빠르게 만들 수 있다.
** Ctrl + R 두 번으로 이름을 한 번에 수정할 수 있다.

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

public class Movement : MonoBehaviour
{
    private Rigidbody rigid;
    [SerializeField]
    private float mod = 100f;
    [SerializeField]
    private float rotationSpeed = 1f;
    void Start()
    {
        rigid = GetComponent<Rigidbody>();
    }

    void Update()
    {
        ProcessThrust();
        ProcessRotation();
    }

    void ProcessThrust()
    {
        if (Input.GetKey(KeyCode.Space))
        {
            rigid.AddRelativeForce(Vector3.up * mod * Time.deltaTime); // Time.deltaTime은 1프레임당 시간
        }
    }

    void ProcessRotation()
    {
        if (Input.GetKey(KeyCode.A))
        {
            // Ctrl + .으로 반복되는 문장을 함수로 빠르게 만들 수 있다.
            // 반복되는 문장은 다른 것만 매개변수로 받으면 좋다.
            // Ctrl + R 두 번으로 이름을 한 번에 수정할 수 있다.
            ApplyRotation(rotationSpeed);
        }
        else if (Input.GetKey(KeyCode.D))
        {
            ApplyRotation(-rotationSpeed);
        }
    }

    private void ApplyRotation(float rotationThisFrame)
    {
        transform.Rotate(Vector3.forward * rotationThisFrame * Time.deltaTime);
    }
}

 

 

Rigidbody Constraints

Rigidbody의 Constraints에서 위치와 회전 값을 고정할 수 있다.

Rigidbody의 Constaraints

물체에 부딪혔을 때 회전이 마음대로 안 되는 버그가 있다. (충돌 후 물리 계산 방향과 다른 방향으로 움직일려고 해서 버그가 발생함)

* 해결 방안 : 물리적 충돌에 의한 회전과 transform을 기반으로 한 회전은 다르기 때문에 물리적 충돌의 제약을 걸어 묶어준 후 수동으로 transform 회전을 하고 수동 회전 입력이 없으면 물리적 충돌의 제약을 푼다.  

물리적 충돌과 transform 회전

 

Rigidbody Drag

Drag 값은 공기 저항 값으로 움직일 때 저항이 발생한다.

물리적 힘을 줬을 때 어느정도 까지만 가고 더 추진 되지 않는다.

 

Physics Gravity

Project Setting - Physics - Gravity에서 월드 중력 값을 조정할 수 있다.

ex) 플레이어가 뚫고 가야할 맞바람 구현 - x축으로 -값을 줌

* 플레이 화면에서 고쳐도 저장 안 됨 => 플레이 중 테스트 가능

Gravity

 

Movement.cs

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

public class Movement : MonoBehaviour
{
    private Rigidbody rigid;
    [SerializeField]
    private float mod = 100f;
    [SerializeField]
    private float rotationSpeed = 1f;
    void Start()
    {
        rigid = GetComponent<Rigidbody>();
    }

    void Update()
    {
        ProcessThrust();
        ProcessRotation();
    }

    void ProcessThrust()
    {
        if (Input.GetKey(KeyCode.Space))
        {
            rigid.AddRelativeForce(Vector3.up * mod * Time.deltaTime); // Time.deltaTime은 1프레임당 시간
        }
    }

    void ProcessRotation()
    {
        if (Input.GetKey(KeyCode.A))
        {
            // Ctrl + .으로 반복되는 문장을 함수로 빠르게 만들 수 있다.
            // 반복되는 문장은 다른 것만 매개변수로 받으면 좋다.
            // Ctrl + R 두 번으로 이름을 한 번에 수정할 수 있다.
            ApplyRotation(rotationSpeed);
        }
        else if (Input.GetKey(KeyCode.D))
        {
            ApplyRotation(-rotationSpeed);
        }
    }

    private void ApplyRotation(float rotationThisFrame)
    {
        // 비트연산이라 더하면 xy 값 물리적 고정과 같음
        // rigid.constraints = (RigidbodyConstraints)((int)RigidbodyConstraints.FreezeRotationX + (int)RigidbodyConstraints.FreezeRotationY);
        // 물리적으로 회전 고정
        // rigid.constraints = RigidbodyConstraints.FreezeRotation;
        
        rigid.freezeRotation = true; // 회전 값을 고정해서 수동으로 회전을 조작할 수 있게 함
        // 이게 되는 이유는 rigid(물리)충돌의 회전만 제어했을 뿐이지 transform 기반으로 한 회전은 수동으로 제어 가능 
        transform.Rotate(Vector3.forward * rotationThisFrame * Time.deltaTime);
        rigid.freezeRotation = false; // 회전 값 고정을 풀어서 물리 시스템이 적용 됨
    }
}

Rotate

'유데미 강의 > C#과 Unity로 3D 게임 개발하기 : 부스트 프로젝트' 카테고리의 다른 글

유니티 오디오  (0) 2022.08.12
소스 컨트롤  (0) 2022.08.12
부스터  (0) 2022.08.03
클래스, Input 클래스  (0) 2022.08.03
유니티 유닛  (0) 2022.08.03

부스터

RigidBody.AddRelativeForce(Vector3 vec)

상대적인 힘 (특정 개체의 좌표 혹은 변형 정보를 기반으로 힘을 가함)

RigidBody.AddForce(Vector3 vec)은 절대적인 힘 (월드좌표 기준)

 

Movement.cs

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

public class Movement : MonoBehaviour
{
    private Rigidbody rigid;
    [SerializeField]
    private float mod = 100f;
    void Start()
    {
        rigid = GetComponent<Rigidbody>();
    }

    void Update()
    {
        ProcessThrust();
        ProcessRotation();
    }

    void ProcessThrust()
    {
        if (Input.GetKey(KeyCode.Space))
        {
            rigid.AddRelativeForce(Vector3.up * mod * Time.deltaTime); // Time.deltaTime은 1프레임당 시간
        }
    }

    void ProcessRotation()
    {
        if (Input.GetKey(KeyCode.A))
        {
            Debug.Log("rotate left");
        }
        else if (Input.GetKey(KeyCode.D))
        {
            Debug.Log("rotate right");
        }
    }

}

클래스

- 코드를 정리할 때 사용되고 비슷한 것들을 그룹화할 수 있게 해줌

- 변수와 메서드를 보관하는 매우 유용한 용기임

- 보통 여러 개의 일이 아닌 하나의 주된 일을 하도록 구성됨 => 코드를 읽기도 쉽고 문제 해결도 편하고 여러 사람이랑 프로젝트를 작업하기 편하다.

ex) 움직임, 충돌 처리기, 슈팅, 점수, 적 인공지능 등

 

유니티 내장 클래스

- 유니티가 사용하기 좋게 이미 만들어 놓은 클래스

- 클래스에 접근하면 안에 있는 컨텐츠에 접근하는 것임

- .연산자를 통해 접근한다.

ex) 

클래스이름.메서드이름();

ClassName.MethodName();

Input클래스는 플레이어가 키를 눌렀을 때 어떤 키를 눌렀는지에 대한 정보가 'Input'에 저장되어 있음

Input.anyKey // 키 입력이 들어왔는지 체크하는 프로퍼티(bool형 값)

Input.GetKeyDown(KeyCode.Space) // 플레이어가 Space를 눌렀을 때 체크하는 메서드(bool형 반환)

  

 

Input 클래스

Input.GetKey vs GetKeyDown vs GetKeyUp

// 키가 눌려졌을 때 1번
Input.GetKeyDown()

// 키를 누르고 있을 때 계속
Input.GetKey()

// 눌렀던 키를 뗐을 때 1번
Input.GetKeyUp()

 

매개변수가 다른 경우

메서드가 매개변수 형태를 둘 다 허용하는 경우다.

- 위아래 화살표로 페이지를 넘길 수 있다.

* 문자열 참조는 안 하는 게 좋다 - 오류가 생길 확률이 증가(실수)

* 만약 해당 시그니처 옵션(매개변수 형태가 보이는 창)이 사라졌을 때 Ctrl + Shift + Space를 누르면 다시 창이 뜬다.

Input.GetLKey(KeyCode)
Input.GetKey(string)

 

Movement.cs

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

public class Movement : MonoBehaviour
{
    void Start()
    {
    }

    void Update()
    {
        // 키가 눌려졌을 때 1번
        // Input.GetKeyDown()

        // 키를 누르고 있을 때 계속
        // Input.GetKey()

        // 눌렀던 키를 뗐을 때
        // Input.GetKeyUp()

        ProcessThrust();
        ProcessRotation();
    }

    void ProcessThrust()
    {
        // Input.GetKey("Space");
        if (Input.GetKey(KeyCode.Space))
        {
            Debug.Log("Pressed SPACE - Thrusting");
        }
    }

    void ProcessRotation()
    {
        // 왼쪽으로 회전하면서 오른쪽으로 회전할 수는 없으므로
        if (Input.GetKey(KeyCode.A))
        {
            Debug.Log("rotate left");
        }


        // 여기서 else는 위의 if문에만 해당됨
        else if (Input.GetKey(KeyCode.D))
        {
            Debug.Log("rotate right");
        }
    }

}

실행

 

코드를 어디에 캡슐화 하는가?

캡슐 : 코드의 부분마다 알아야하는 기초 수준의 접근

- 모든 것이 서로에게 접근할 수 없도록 하면 좋음

ex) Movement 클래스에 있는 메서드만 움직임을 수정 할 수 있음 - 두 세개의 클래스가 움직임을 같이 처리하면 실제로 속도가 무엇이어야 하는지와 어떤 것이 진짜인지 헷갈릴 수 있음

구조

러시아 인형인 마트료시카처럼 구성됨

ex) 작은 인형이 큰 인형에 들어있고 또 그 인형이 더 큰 인형에 들어있음 == 실행문이 메서드에 들어있고 메서드는 클래스에 보관되며 클래스는 전체 시스템의 네임 스페이스에 들어간다.

 

 

+ Recent posts