Devlog/Unity

[Unity: C#] VS Code로 script 작성하기 - 초기셋팅 / 참고사항

FATKITTY 2021. 9. 13. 17:44
반응형

초기 셋팅

 

1. Extensions에서 C# extension을 설치해준다.
VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp 

 

2. .NET Core를 설치한 적이 없다면 설치해준다.

.NET Framework 4.8: https://dotnet.microsoft.com/download/dotnet-framework/thank-you/net48-developer-pack-offline-installer

 

3. Unity에서 기본 Script Editor를 VS Code로 설정해준다.

Edit → Preferences → External Tools → External Script Editor → Visual Studio Code 선택

그 후 밑에 Generate .csproj files for: 밑의 체크박스를 모두 체크해준 뒤 Regenerate project files를 클릭해준다.

 

4. VS Code 좌측 하단에 불꽃 모양 아이콘이 떠야 언어 서버 프로토콜이 잘 실행되고 있다는 뜻.

뭔가 잘 안 된다면 터미널을 열고 Output에서 OmniSharp Log를 확인해보고 에러를 확인해보면 된다.

 

 

참고사항

 

- 명명규칙

  • Pascal case - 클래스, 함수명
  • Camel case - 변수명

 

- 파일명 변경

: Unity Project view에서 script 파일의 이름을 변경하면 물리적 파일명만 변경될 뿐,

스크립트 내에 정의된 클래스명은 동기화가 안 된다.

따라서 만약 파일명을 변경해야 한다면 코드 편집기(VS Code)에서 클래스명을 수동으로 변경해줘야 한다.

변경된 파일명과 수정한 클래스명이 오탈자 없이 정확히 일치해야 한다.

서로 일치하지 않으면 오류가 생기면서 프로젝트 빌드가 안 될 것이다.

 

- private 변수를 Inspector에서 확인하고 싶을 때

: Inspector 우클릭 → Debug mode 선택해주면 private 변수도 read-only로 표시된다.

디버깅 작업이 끝나면 normal mode로 다시 변경해준다.

 

- 스크립트 실행 순서

: Execution Order... 메뉴에서 스크립트 우선순위 설정이 가능하다.

 

- Unity 고유 함수, 문법, 개념 참고용 예시 code

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

public class PlayerCtrl : MonoBehaviour
{
    /*
    void Awake()
    {
        // 처음 한번만 실행.
        // Start보다 먼저 호출됨.
        // Initialize, game data 전체 초기화
    }

    void OnEnable()
    {
        // event 함수. 매번 호출됨.
    }
    */

    private Animation anim;

    // 전역변수 이동, 회전 속도
    public float moveSpeed = 8.0f;
    public float turnSpeed = 100.0f;

    // Start is called before the first frame update
    // 처음 한번만 실행
    void Start()
    {
        // 컴포넌트를 추출해서 변수에 대입
        // anim = this.gameObject.GetComponent<Animation>();
        // 편의상 this.gameObject는 생략해서 사용
        anim = GetComponent<Animation>();

        anim.Play("Idle");
    }

    /* Update is called once per frame
    프레임 드랍 현상 때문에 호출이 불규칙적
    렌더링하는 주기와 동일
    최대한 간소화 하는게 좋음
    ex. 주인공 이동 로직 */
    void Update()
    {
        // -1.0f ~ 0.0f ~ +1.0f 값이 return됨.
        float h = Input.GetAxis("Horizontal");  // left, right
        float v = Input.GetAxis("Vertical");  // up, down
        float r = Input.GetAxis("Mouse X");  // mouse cursor left, right

        // (전진후진벡터) + (좌우벡터)
        Vector3 dir = (Vector3.forward * v) + (Vector3.right * h);

        // 이동처리
        transform.Translate(dir.normalized * Time.deltaTime * moveSpeed);

        // 회전처리
        transform.Rotate(Vector3.up * Time.deltaTime * turnSpeed * r);

        /*
            정규화 벡터(Normalized Vector), 단위 벡터(Unit Vector)
            Vector3.forward     = Vector3(0, 0, 1)
            Vector3.up          = Vector3(0, 1, 0)
            Vector3.right       = Vector3(1, 0, 0)
            반대방향은 *(-1)

            Vector3.one         = Vector3(1, 1, 1)
            Vector3.zero        = Vector3.(0, 0, 0)
        */

        // 애니메이션 처리
        PlayerAnim(h, v);
    }

    void PlayerAnim(float h, float v)
    {
        if (v >= 0.1f)  // 전진
        {
            // 애니메이션을 부드럽게 전환
            anim.CrossFade("RunF", 0.3f);
        }
        else if (v <= -0.1f)  // 후진
        {
            anim.CrossFade("RunB", 0.3f);
        }
        else if (h >= 0.1f)  // 오른쪽
        {
            anim.CrossFade("RunR", 0.3f);
        }
        else if (h <= -0.1f)  // 왼쪽
        {
            anim.CrossFade("RunL", 0.3f);
        }
        else {
            anim.CrossFade("Idle", 0.3f);
        }
    }

    /*
    void FixedUpdate()
    {
        // 호출되는 간격이 규칙적. (0.02s 간격으로 호출)
        // 물리 엔진이 백그라운드에서 계산하는 속도
    }

    
    void LateUpdate()
    {
        // Update 후 LateUpdate 실행
        // Update 계산 결과로 후처리 작업 실행
        // 반드시 계산처리가 끝난 후 실행되어야 함.
        // ex. 주인공 따라가는 카메라 로직
    }
    */
}

/*
    Animation Type

    - Legacy : 하위 호환성, 속도가 빠르지만 오직 코드로만 조종 가능. Animation 컴포넌트

    - Mecanim: Visual Editor 제공됨. Animator 컴포넌트
        - Generic
        - Humanoid : Retargeting, 이족보행, 15개의 필수 bones 필요
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(AudioSource))]
// audio source 삭제 방지
public class FireCtrl : MonoBehaviour
{
    // private 상태 유지하면서 inspector에 노출할 수 있음
    [SerializeField]
    private new AudioSource audio;

    public GameObject bulletPrefab;
    public Transform firePos;
    public AudioClip fireSfx;

    [HideInInspector]  // Unity 문법
    // C# 문법인 [System.NonSerialized] 도 사용 가능
    public MeshRenderer muzzleFlash;

    // Start is called before the first frame update
    void Start()
    {
        audio = GetComponent<AudioSource>();
        muzzleFlash = firePos.GetComponentInChildren<MeshRenderer>();
        muzzleFlash.enabled = false;
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0) == true)
        {
            Fire();
        }
    }

    // 총알 생성하는 함수 따로 생성 (Update 줄이기 위해)
    void Fire()
    {
        // 총알 생성
        // Instantiate (생성할객체, 위치, 각도)
        Instantiate(bulletPrefab, firePos.position, firePos.rotation);
        // 사운드 발생 (sound, volume scale)
        audio.PlayOneShot(fireSfx, 0.8f);

        // 총구화염 효과
        StartCoroutine(ShowMuzzleFlash());
    }

    // coroutine 함수 - multi thread처럼 처리해줌
    IEnumerator ShowMuzzleFlash()
    {
        /*
            총 4장으로 분리. (0, 0), (0.5, 0), (0, 0.5), (0.5, 0.5)
            0 ~ 0.5 사이의 난수 생성
            Random.Range는 (int, int)면 마지막 인자를 포함 x, (float, float)는 포함 o
            Random.Range(0, 3) ==> 0, 1, 2 
            Random.Range(0.0f, 3.0f) ==> 0.0f ~ 3.0f
        */

        Vector2 offset = new Vector2(Random.Range(0, 2) * 0.5f, Random.Range(0, 2) * 0.5f);
        muzzleFlash.material.mainTextureOffset = offset;

        // 크기변경
        float scale = Random.Range(1.0f, 3.0f);
        muzzleFlash.transform.localScale = Vector3.one * scale;

        // MuzzleFlash의 회전
        float angle = Random.Range(0, 360);
        muzzleFlash.transform.localRotation = Quaternion.Euler(Vector3.forward * angle);

        // MeshRenderer 컴포넌트를 활성화
        muzzleFlash.enabled = true;

        // coroutine을 이용해서 waiting 걸어주기
        yield return new WaitForSeconds(0.2f);

        // MeshRenderer 컴포넌트를 비활성화
        muzzleFlash.enabled = false;
    }
}

 

반응형