1학년 1학기 여름방학 때 동기들과 함께 2022 메타버스 개발자 경진대회에 참가했다.

우리는 360헥사월드를 이용해 직접 랜드마크 건물들을 만들고 유니티로 미래의 서울을 만드는 과제를 맡았다.

 

아래의 영상들이 1학년 5명이 모여 열심히 작업한 결과물을 담은 영상이다.

 

아래의 영상은 우리 팀의 팀장 방모씨가 우리의 결과물을 직접 나레이션하여 제작한 영상이다.

 

 

결과는 1차합격 후 2차에서 떨어졌다. (ㅠㅠ)

1차 합격 당시 매우 기쁜 상태를 보여주는 인스타 스토리다..ㅎㅎ

2차에서 떨어져 무척이나 아쉬웠다. 1차 합격한 후 2차를 위해 더 많은 아이디어를 내고 준비하고 있었던 우리였기 때문이다. 상심이 컸지만 지금 생각하면 정말 좋은 경험이라 생각된다. 

'game > unity(C#)' 카테고리의 다른 글

나만의 리듬게임 만들기 - 3  (0) 2022.09.13
나만의 리듬게임 개발일지 - 2  (0) 2022.08.10
나만의 리듬게임 개발일지 - 1  (0) 2022.07.27
2D 기초 - 3 (Jump 구현)  (0) 2022.07.21
2D 기초 - 2 (Player 이동 구현)  (0) 2022.07.14

베토벤 바이러스로 게임을 만들기 전에 World's Smallest Violin에서 박자감이 좋은 부분을 따와서 간단한 stage를 만들었다.

박자에 맞춰 pointbox를 배치할 때에는 직접 리듬에 맞춰 플레이하고 Debug를 이용해 위치를 확인한 후 배치했다.

 

배치 후 플레이 영상이다.

 

30초 밖에 되지 않는 음악을 리듬 게임으로 만들었지만 느낀 점이 있다.

첫째, 실행할 때 마다 음악 싱크가 제각각이다.

그냥 bgm으로 음악을 실행하는 것이라면 딱히 문제가 되지 않았겠지만 리듬 게임을 만들다보니 크게 체감 되었다. 전체 실행 횟수 중 30퍼센트 가량 싱크가 안맞았기 때문에 계속해서 pointbox의 위치를 수정하다가 흥미를 잃었다.

둘째, 내가 리듬게임을 못하는 것 같다.

pointbox의 위치가 알맞은지, 벽의 폭이 적당한지를 알아보기 위해 테스트를 하는데 쉽지 않았다.

 

pointbox를 먹었을 때의 이펙트, 카메라 회전, 생동감 있는 player와 게임 화면 등을 개선시켜 좀 더 재밌는 게임처럼 만들고자 했으나 여러가지의 이유로 나만의 리듬게임 만들기는 여기까지 하는 것으로 정했다.

먼저 벽과 공(캐릭터)간의 충돌을 감지할 수 있도록 했다.

 

    private void OnCollisionEnter2D(Collision2D other) 
    {
        if (other.gameObject.tag == "Wall")
        {
            Debug.Log("GameOver");
        }
    }

 

간단하게 콘솔창을 통해 충돌을 감지하는지 확인했다.

 


그 후에는 player가 pointbox에서 키를 눌려 점수를 올릴 수 있도록 했다.

 

Player c#스크립트

public class PlayerMove : MonoBehaviour
{   
    public bool isPoint = false;
    public int point = 0;
    public float Speed;
    private int directionIs = 0;
    Rigidbody2D rigid;

    // Start is called before the first frame update
    void Awake()
    {

    }

    // Update is called once per frame
    void Update()
    {
        Rotation();
        Rotate();
    }

    void FixedUpdate() 
    {
        Move();
    }
    private void Rotation()
    {
        //키입력 시에 방향전환
        if (Input.GetKeyDown(KeyCode.D))
        {
            if (directionIs == 0)
                directionIs = 3;
            else
                directionIs = 0;
        }
        if (Input.GetKeyDown(KeyCode.A))
        {
            if (directionIs == 1)
                directionIs = 2;
            else
                directionIs = 1;
        }
        
    }

    private void Move()
    {
        if (directionIs==0)
            transform.position = new Vector2(transform.position.x, transform.position.y + Speed);
        else if (directionIs==1)
            transform.position = new Vector2(transform.position.x + Speed, transform.position.y);
        else if (directionIs==2)
            transform.position = new Vector2(transform.position.x - Speed, transform.position.y);
        else if (directionIs==3)
            transform.position = new Vector2(transform.position.x, transform.position.y - Speed); 
    }

    private void OnCollisionEnter2D(Collision2D other) 
    {
        if (other.gameObject.tag == "Wall")
        {
            Debug.Log("GameOver");
        }
    }

    private void OnTriggerEnter2D(Collider2D other) 
    {
        if (other.gameObject.tag == "PointBox")
        {
            isPoint = true;
        }
    }

    private void Rotate() //부드럽게 만들기
    {
        if (Input.GetMouseButtonDown(0))
        {
            for(int i=1; i<91; i++)
            {
                transform.Rotate(0, 0, i);
            }
        }
    }
    private void OnTriggerExit2D(Collider2D other) 
    {
        if (other.gameObject.name == "PointBox")
        {
            isPoint = false;
        }
    }
}

 

pointbox c#스크립트

public class Point : MonoBehaviour
{
    public GameObject PlayerMove;
    private bool istouch = false;
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        Delete();
    }

    private void Delete()
    {
        if ((Input.GetKeyDown(KeyCode.Space)||Input.GetKeyDown(KeyCode.A)||Input.GetKeyDown(KeyCode.D))&&PlayerMove.GetComponent<PlayerMove>().isPoint&&istouch)
        {
            PlayerMove.GetComponent<PlayerMove>().point++;
            print(PlayerMove.GetComponent<PlayerMove>().point);
            Destroy(this.gameObject);
        }
    }

    private void OnTriggerEnter2D(Collider2D other) 
    {
        if (other.gameObject.name == "Player")
        {
            istouch = true;
        }
    } 

    private void OnTriggerExit2D(Collider2D other) 
    {
        if (other.gameObject.tag == "Player")
        {
            istouch = false;
        }
    }

}

 

'A' 키를 눌러야 할 때에는 빨강색, 'D'는 파랑색으로 지정했다. 

그리고 지난번 방향 전환에서 좀 더 추가해서 'A' 키는 좌우를, 'D'키는 위아래를 움직일 수 있도록 했다.

 

첫번째로 만들 리듬게임의 음악은 '베토벤 바이러스'로 정했다. 그 후 turn 혹은 space바를 눌러야하는 지점에 pointbox를 깔아주었다.

 

Player가 pointbox와 닿았을 때 키를 누르면 pointbox가 사라지도록 하기 위해 OnTriggerEnter2D 함수 안에서 Input을 사용해봤지만 생각대로 작동하지 않았다. 그 이유는 OnTriggerEnter는 1 프레임에만 사용되기 때문이였다. 동일한 프레임(1 프레임에만 해당)에서 키를 눌러야 작동하는 것이었다. 

그래서 bool 변수를 하나 선언해서 trigger 안에 있을 때와 없을 때 각각 OntriggerEnter와 OntriggerExit를 이용해 bool 값을 지정해주었고, pointbox에 적용할 스크립트를 생성해 player에 적용한 스크립트에서 bool 변수를 가져와 pointbox에 닿았을 때 키를 누르면 pointbox가 사라지도록 만들었다.

 

일단 이정도까지 하고 난 뒤 게임을 실행했을 때 하나의 pointbox를 먹으면 모든 pointbox가 사라지는 문제가 발생했다. 그래서 pointbox의 c# 스크립트에서 onTriggerEnter과 onTriggerExit를 이용해 문제를 해결했다.

 

<실행영상>

 

나는 공부를 하거나 코딩, 인터넷 서칭을 할 때 음악을 거의 항상 듣는다. 노래를 들으며 수학 문제를 풀면 어느 순간 노래의 박자나 리듬을 타며 신나게 문제를 풀고 있는 나를 종종 발견할 수 있었다.

노래의 리듬을 타며 할 일을 하는 것이 나에게는 힐링으로 다가왔고, 내가 좋아하는 노래를 내가 주로 탔던 리듬으로 리듬 게임을 만들고 싶다는 생각으로 이어졌다.

내가 주로 리듬을 타며 들었던 노래들은 팝송이었는데, 유명한 팝송을 이용해 게임을 만들 경우에는 저작권 침해 문제가 발생할 것이라고 생각되어 팝송으로 리듬게임을 만드는 것은 포기했다.

그래서 '베토벤 바이러스'와 같이 음악의 저작권자가 사망한지 70년이 지난 음악들이나 무료로 풀리는 음악들로만 만들고자 한다.

 

많은 리듬게임이 있지만 그중 다수의 게임들은 외우지 않으면 눈감고 클리어를 할 수 없었다. 어릴 때 부터 꽤나 많은 리듬게임들을 해왔지만 나는 보고 누르는 것이 느려 항상 리듬게임을 즐겁게 플레이 하지 못했다. 귀보다는 눈이 더 열일 하는 느낌이 강했다. 그래서 나는 귀가 조금 더 열일 하는 나를 위한 리듬게임을 만들고자 한다. (얼불춤처럼)

 

게임 형태(컨셉)에 관해 일주일동안 고민해 많고 좋은 컨셉들을 생각해냈지만 아직 아는 것이 거의 없는 점을 고려해 실현 가능한 형태로 골랐다.

간단하게 소개하자면 player가 박자에 맞춰 방향 전환을 하며 지그재그로 된 통로에 부딪히지 않는 2D 게임이다.

방향 키는 'A'와 'D' 두 개를 이용할 예정이고, pc 버전으로 먼저 만들고 모바일 버전도 만들어 볼 예정이다.

 

현재까지 작성한 코드는 이러하다.

 

public float Speed;
public int directionIs = 0;

    // Start is called before the first frame update
    void Awake()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        //키입력 시에 방향전환
        if (Input.GetKeyDown(KeyCode.D))
        {
            directionIs = 0;
        }
        if (Input.GetKeyDown(KeyCode.A))
        {
            directionIs = 1;
        }
    }

    void FixedUpdate() 
    {
        //Move
        if (directionIs==0)
            transform.position = new Vector2(transform.position.x, transform.position.y + Speed);
        else if (directionIs==1)
            transform.position = new Vector2(transform.position.x + Speed, transform.position.y);
        
    }

 

기본적인 움직임과 키 입력에 따른 방향전환만 구현했다. 

 

 

테스트를 해보았다.

화면 비율은 9:16으로 했다.

영상을 보니 공은 좀 더 앞쪽으로 배치하는 것이 좋을 것 같다. 

'game > unity(C#)' 카테고리의 다른 글

나만의 리듬게임 만들기 - 3  (0) 2022.09.13
나만의 리듬게임 개발일지 - 2  (0) 2022.08.10
2D 기초 - 3 (Jump 구현)  (0) 2022.07.21
2D 기초 - 2 (Player 이동 구현)  (0) 2022.07.14
2D 기초 - 1 (Component, Animation)  (0) 2022.07.12

jump 후 중력을 받아 바닥으로 떨어질 때 뛸 때와 달리 천천히 떨어진다. 이를 조절하기 위해서는 Project Setting에서 Physics 2D에서 Gravity를 바꿔주거나 Rigidbody 2D에서 Gravity Scale을 바꿔주면 된다.

 

제자리에서 jump를 한다면 animation이 breath - jump - breath 순으로 바뀌어야 한다.

이를 위해 오브젝트 검색을 위해 Ray를 쏘는 방식인 RayCast를 이용했다.

DrawRay() - 에디터 상에서만 Ray를 그려주는 함수

Debug이므로 실제 게임창에는 나타나지 않는다.

RayCastHit 변수의 콜라이더로 검색 확인이 가능하다.

LayerMask - 물리 효과를 구분하는 정수값

 

jump animation이 추가되므로 다음과 같이 animator를 설정해주면 된다. <해야할 것>은 똑같다.

 

<코드>

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

public class PlayerMove : MonoBehaviour
{
    public float maxSpeed;
    public float jumpPower;
    Rigidbody2D rigid;
    SpriteRenderer spriteRenderer;
    Animator anim;

    // Start is called before the first frame update
    void Awake() {
        rigid = GetComponent<Rigidbody2D>();
        spriteRenderer = GetComponent<SpriteRenderer>();
        anim = GetComponent<Animator>();
    }
    // Update is called once per frame

    void Update()
    {   //Jump
        if(Input.GetButtonDown("Jump") && !anim.GetBool("isJumping")){
            rigid.AddForce(Vector2.up*jumpPower, ForceMode2D.Impulse);
            anim.SetBool("isJumping",true);}

        //Stop Speed 
        if(Input.GetButtonUp("Horizontal")){ 
            rigid.velocity = new Vector2(rigid.velocity.normalized.x*0.2f, rigid.velocity.y);
        }
        
        //Direction Sprite
        if(Input.GetButton("Horizontal")){
            spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == -1;
        }

        //Walk <-> Breath
        if(Mathf.Abs(rigid.velocity.x)<0.3f)
            anim.SetBool("isWalking",false);
        else
            anim.SetBool("isWalking",true);
    
    }


    void FixedUpdate()
    {
        //Move By Control
        float h=Input.GetAxisRaw("Horizontal");
        rigid.AddForce(Vector2.right*h,ForceMode2D.Impulse);
        if(rigid.velocity.x > maxSpeed)
            rigid.velocity = new Vector2(maxSpeed, rigid.velocity.y); // Right Max Speed
        else if(rigid.velocity.x < maxSpeed*(-1))
            rigid.velocity = new Vector2(maxSpeed*(-1), rigid.velocity.y); // Left Max Speed

        //Landing Platform
        if(rigid.velocity.y < 0){

            Debug.DrawRay(rigid.position, Vector3.down, new Color(0,1,0));

            RaycastHit2D rayHit = Physics2D.Raycast(rigid.position, Vector3.down, 1, LayerMask.GetMask("platform"));

            if(rayHit.collider != null){
                if(rayHit.distance < 0.5f){
                    anim.SetBool("isJumping", false);
                }
            }
        }
        
    }
}

Player 이동 구현

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

public class PlayerMove : MonoBehaviour
{
    public float maxSpeed;
    Rigidbody2D rigid;
    SpriteRenderer spriteRenderer;
    Animator anim;

    // Start is called before the first frame update
    void Awake() {
        rigid = GetComponent<Rigidbody2D>();
        spriteRenderer = GetComponent<SpriteRenderer>();
        anim = GetComponent<Animator>();
    }
    // Update is called once per frame

    void Update()
    {   
        //Stop Speed 
        if(Input.GetButtonUp("Horizontal")){ 
            rigid.velocity = new Vector2(rigid.velocity.normalized.x*0.2f, rigid.velocity.y);
        }
        
        //Direction Sprite
        if(Input.GetButtonDown("Horizontal")){
            spriteRenderer.flipX = Input.GetAxisRaw("Horizontal") == -1;
        }
		
        //Walk <-> Breath
        if(Mathf.Abs(rigid.velocity.x)<0.3f)
            anim.SetBool("isWalking",false);
        else
            anim.SetBool("isWalking",true);
    }
    void FixedUpdate()
    {
        //Move By Control
        float h=Input.GetAxisRaw("Horizontal");
        rigid.AddForce(Vector2.right*h,ForceMode2D.Impulse);
        if(rigid.velocity.x > maxSpeed)
            rigid.velocity = new Vector2(maxSpeed, rigid.velocity.y); // Right Max Speed
        else if(rigid.velocity.x < maxSpeed*(-1))
            rigid.velocity = new Vector2(maxSpeed*(-1), rigid.velocity.y); // Left Max Speed
    }
}

 

단발적인 키 입력은 Updated에서, 계속적인 키 입력은 FixedUpdate에서 해준다.

 

Unity에 있는 기능들을 C# 스크립트로 불러와 적절하게 사용할 수 있다. 이때, 초기화 해주는 것을 잊지 말자.

 

public으로 maxSpeed 변수를 생성해주면 유니티에서 값을 넣어주는 칸이 생성되어 편하다.

 

normalized - 벡터의 크기를 1로 만든 상태이다. (단위벡터)

선형대수학을 배울 때 단위벡터는 방향을 나타내기 위해 많이 쓰였는데 유니티에서도 마찬가지다.

 

python에서의 절댓값 함수 abs와 같은 기능을 하는 것은 Mathf.Abs이다.

Mathf는 수학 관련 함수를 제공하는 class이다.

 


Friction

player가 원활하게 움직일 수 있도록 Physics Material 2D를 생성해 마찰력을 적당히 지정해준다.

참고로 Friction이 마찰력이며, 0으로 지정해줄 경우 마찰력이 없는 빙판과 같다.

오르막길을 잘 오를 수 있도록 하기 위해서 마찰력을 0으로 설정해주었다.

만든 재질을 지형의 Collider 2D - Material에 끌어다 넣어주면 잘 적용된다.

 

 

Rigid Body에서 공기저항 

Linear Drag - 공기저항, 이동 시 속도를 느리게 해준다. 보통 1~2로 설정해준다.

 

 


 

Animator 설정

움직이는 상태, 멈추고 있는 상태 등 상황에 따라 나타낼 player의 animation은 다르므로 코드와 함께 animator를 수정해줘야 한다. breath가 default state인 상태에서 player가 움직일 경우에는 walk 동작을 해야하므로 마우스 우클릭을 통해 breath에서 walk로의 화살표를 만들어 줘야한다. 움직이다가 멈추는 경우도 있으므로 walk에서 breath를 향하는 화살표 또한 만들어 줘야 한다.

 

 

<해야 할 것>

1. Has Exit Time끄기

2. 구간닫기

3. 매개변수 설정

 

 

'game > unity(C#)' 카테고리의 다른 글

나만의 리듬게임 개발일지 - 1  (0) 2022.07.27
2D 기초 - 3 (Jump 구현)  (0) 2022.07.21
2D 기초 - 1 (Component, Animation)  (0) 2022.07.12
Visual Studio Code 자동 완성이 되지 않는 오류  (0) 2022.07.12
0404) C# 기초 - 3  (0) 2022.04.04

Component

collider 2D - 물리 충돌 처리를 해준다. Box collider, circle collider 등 다양한 형태의 collider이 있다.

rigid body 2D - rigid body를 한국어로 하면 강체인데, 강체란 물리학에서 형태가 고정되어 변하지 않는 물체이다. 

이 component를 추가하면 중력이 작용하게 된다.

3D와 똑같은 기능을 하지만 2D에서는 2D가 붙은 component를 추가해야 한다.

 

 

Animation

하나의 캐릭터가 여러가지 동작(숨쉬기, 점프, 걷기 등)을 하게 되면 한 캐릭터에 여러 개의 animation이 들어가게 된다.

이 경우에 바라던대로 animation이 작동하지 않을 수 있는데,

해결 방법은 유니티 상단 바에 있는 window에서 animator 창을 열어 default state를 바꿔주는 것이다.

 

animator 창을 열면 다음과 같이 되어있는 것을 확인할 수 있다.

나는 캐릭터가 걷는 것을 계속하지 않고 숨 쉬기를 계속하기를 원하기 때문에 breath를 default state로 바꿔주었다.

방법은 마우스 우클릭으로 박스를 눌러 Set as Layer Default State로 설정해주면 된다.

 

'game > unity(C#)' 카테고리의 다른 글

2D 기초 - 3 (Jump 구현)  (0) 2022.07.21
2D 기초 - 2 (Player 이동 구현)  (0) 2022.07.14
Visual Studio Code 자동 완성이 되지 않는 오류  (0) 2022.07.12
0404) C# 기초 - 3  (0) 2022.04.04
0401) C# 기초 - 2  (0) 2022.04.01

유니티와 vsc를 연동해 c# script를 작성하고 있는 도중 이전에는 잘 되던 자동 완성이 되지 않는 현상을 발견했다.

자동 완성이 되지 않는 것은 정말 비효율적인 작업을 초래하므로 최대한 빠르게 해결 방법을 찾는 것이 좋다.

 

최근 c# 확장 프로그램이 업데이트 되면서 발생한 현상인 것 같다.

 


 

해결방법

 

C# 확장 프로그램이 아마 1.25.0 버전일텐데 이를 제거 오른쪽에 있는 화살표 버튼을 눌러 1.24.4 버전으로 재설치 해주면 된다.

'game > unity(C#)' 카테고리의 다른 글

2D 기초 - 2 (Player 이동 구현)  (0) 2022.07.14
2D 기초 - 1 (Component, Animation)  (0) 2022.07.12
0404) C# 기초 - 3  (0) 2022.04.04
0401) C# 기초 - 2  (0) 2022.04.01
0331) C# 기초 - 1  (0) 2022.03.31
int[] exp = {50, 100, 150, 200, 250};
int[] exp2;

 

이렇게 배열을 선언해 줄 수 있다. 배열은 비슷한 성격을 가진 변수들의 집합체이다. 

배열의 값을 참조하고 싶을 때에는 

 

print(exp[0]); //50 (0부터 카운팅하므로)

 

배열의 값을 참조하고 싶을 때에는 위와 같이 하면 된다. (파이썬 공부할 때 배웠던 내용과 동일함)

배열의 원소 개수를 알고 싶을 때 파이썬에서는 len함수를 이용했겠지만 C#에서는 exp.Length를 통해 알 수 있다.

 

int [] array = new int[10];

 

이렇게 하는 것은 배열의 크기(원소의 개수)만 지정해주는 것이다. 

 

방금까지 한 것은 1차원 배열이다.

2차원 배열은 다음과 같이 나타낼 수 있다. (그 이상의 배열들의 형식은 2차원 배열이 생성되는 형식과 유사하다)

 

int[,] array2 = { {1, 2, 3, 4, 5} , {10, 20, 30, 40, 50} };
print(array2[1,3]);

 

코드를 실행해보면 print의 값이 40으로 나오는 것을 알 수 있다. array2[1,3]는 두 배열중 인덱스 1에 해당하는 배열에서의 인덱스 3의 값을 의미한다.

 

그런데 배열은 한번 생성되면 배열의 크기가 고정되어 원소를 늘리거나 줄일 수 없다.

이러한 단점을 극복하는 것이 컬렉션(리스트, 큐, 스텍, 해시테이블, 딕셔너리, 어레이리스트)이다.

 

//ArrayList
ArrayList arrayList = new ArrayList();
arrayList.Add(1); //arrayList에 1이라는 원소를 추가함
arrayList.Add("가나다라");

print(arrayList.Count); //arrayList에서는 length가 없고, Count가 그 기능을 해줌
arrayList[0] = 3; //배열과 사용법은 같음
arrayList.Remove("가나다라"); //직접 지움
arrayList.RemoveAt(0); //인덱스를 통해 지움

 

ArrayList는 누군가가 이미 만들어 놓은 class이다. 점(.)을 찍으면 Add나 Remove같은 메소드를 이용할 수 있다.

 

//List
List<int> list = new List<int>(); //ArrayList와 달리 특정한 자료형만을 원소로 가짐

 

ArrayList는 자료형 상관없이 원소를 가지지만 List는 특정한 자료형을 지정하고, 그 자료형만을 원소로 가진다. 단순히 생각하면 범위가 넓은 ArrayList를 항상 쓰면 더 편하고 좋겠다고 생각되겠지만 범위가 넓은만큼 값이 들어올 때 마다 넓은 Box를 만들고 들어올 때, 나갈 때마다 더 많은 연산이 필요해진다. 즉, 비효율 적인 것이다. 그래서 List보다 더 연산량이 많을 것이고 과부하에 걸리기 쉽다. 

 

//HashTable
HashTable hashTable = new HashTable();
hashTable.Add("만", 10000); //(key, value) 입력
hashTable.Add("백만", 1000000);

print(hashTable["만"]); //인덱스 대신 key로 value를 호출한다

//Dictionary
Dictionary<string, int> dictionary = new Dictionary<string, int>(); //key(string), value(int)

 

HashTable과 Dictionary의 관계는 ArrayList와 List의 관계와 동일하다고 보면 된다.

 

//Queue
Queue<int> queue = new Queue<int>();
queue.Enqueue(5); //원소 5를 넣음
queue.Enqueue(6); //원소 6을 넣음
queue.Dequeue(); //가장 먼저 들어간 원소를 꺼냄
queue.Dequeue(); //두 번째로 들어간 원소를 꺼냄​

 

이 상태에서 queue.Dequeue();를 한번 더 실행하게 된다면 오류가 뜰 것이다. 왜냐면 이미 들어간 총 두개의 원소가 이전에 다 꺼내졌기 때문에 더이상 꺼낼 원소가 없기 때문이다. 그렇기 때문에 queue.Dequeue는 queue.Count!=0일 때에만 실행될 수 있도록 if문과 함께 쓰이는 것이 좋다.

queue는 선입전출이라하고 반대로 후입전출이라고 불리는 stack도 있다.

stack은 queue와 반대로 가장 마지막에 넣었던 원소를 꺼낸다.

 

Stack<int> stack = new Stack<int>();
stack.Push(1); //stack에 1을 넣어줌
stack.Push(2);
stack.Push(3);
stack.pop(); //3을 꺼냄

'game > unity(C#)' 카테고리의 다른 글

2D 기초 - 1 (Component, Animation)  (0) 2022.07.12
Visual Studio Code 자동 완성이 되지 않는 오류  (0) 2022.07.12
0401) C# 기초 - 2  (0) 2022.04.01
0331) C# 기초 - 1  (0) 2022.03.31
메모장  (0) 2022.03.30
  • 변수 이름을 지을 때 intValue 처럼 길어지면 첫글자는 소문자로 쓰고, 중간 단어 첫글자는 대문자로 쓰도록 한다.
  • 함수의 첫글자는 대문자로 쓰도록 하자.

다음과 같이 말이다.

 

public class NewBehaviourScript : MonoBehaviour
{
int intValue;
float floatValue = 10.5f;
float floatValue2 = 20.5f;

void FloatToInt(float _parameter, float _parameter2, string _stringParm = "디폴트값") //함수 생성
{
    intValue=(int)(_parameter+_parameter2);
    print(intValue);
    print(_stringParm);
}

void Start()
{
	FloatToInt(floatValue, floatValue2);
}
}

 

public class에서 지정한 변수들은 함수안에서도 사용 가능하다.(전역변수이므로) 

먼저 함수를 만들어주고 void Start() 안에 함수를 적어주고 이 C# 스크립트를 main camera에 넣어주고 실행시키면 콘솔창에 문제 없이 print됨을 볼 수 있다.

void는 함수의 반환 값이 없을 때 사용한다. 반환 값이 있을 때에는 void대신 반환 값의 형태(int, float 등)를 적어주면 된다.

함수 내에서 다른 함수도 호출시킬 수 있다!

 


public class Test1
{
    private int a;
    public int b;
    public static int c; //공공의 공유자원, 정적 변수
}
public class NewBehaviourScript : MonoBehaviour
{
    Test1 a1;
    Test2 a2;
    
    void Abc()
    {
        a1.b = 5;
        a2.b = 10;
        print(a1.b);
        print(a2.b);
        
        Test1.c = 100; //공유자원은 클래스 자체에 접근
        print(Test1.c);
    }
    void Start() {
        Abc();
    }
}

 

이렇게 private으로 변수를 만들면 다른 class에서는 사용하지 못한다. 하지만 public으로 지정하면 다른 class에서도 사용이 가능하다. 물론 함수도 똑같이 적용된다.

그런데 이런 생각이 들 수 있다. 'public과 private을 왜 굳이 나눠야할까?'

public은 다른 곳에서도 쉽게 접근이 가능하다. 그러므로 보안적인 측면에서 좋지 못할 수 있다. 위의 b가 노출이 되어 제 3자에게 코드를 분석 당할 수 있으니까 말이다.

 

그런데 위 코드를 실행시켜보면 NullReferenceException이라는 오류가 뜨는 것을 확인할 수 있다. 이는 변수에 값이 아무것도 대입되지 않았다는 뜻이다. 

Test1 a1;은 선언만 한것이다. 그래서  Test1 a1 = new Test1(); 이렇게 새롭게 할당을 해주도록 수정해야 한다. 

 

c는 공유자원이므로 a1, a2모두 c의 값으로 100을 가지지만, b는 각각 다른 값을 가지는 것을 알 수 있다.

아직 이 부분이 헷갈리긴 한데, 여러번 실습 하다보면 익숙해지고 완벽하게 이해가 될 것이라고 생각한다.

 


print(a++) vs print(++a)

a++ : 먼저 출력을 한 뒤에 a에 1을 더한다.

 

++a : 출력하기전에 a에 1을 더하고 그 값을 출력한다. 


 

int input = 11;
int num = 10;

switch (input) //조건문
{
    case 10:
        print("input의 값이 10입니다.");
        break;

    case 11:
        print("input의 값이 11입니다.");
        break;
        
    default:
    	print("그 외의 경우");
        break;
}

 

switch case 조건문 다음에는 반드시 break를 써줘야한다. default는 위 케이스에 걸리지 않은 모든 경우에 해당한다.(마치 else와 같은)

 

 

int temp = input == num ? 50 : 100; //삼항 연산자

 

이 코드는 input과 num이 같을 경우에는 temp에 50을, 같지 않을 경우에는 100을 넣어준다는 뜻이다. 이를 삼항 연산자라고 부른다.

 


 

반복문 중 처음 알게된 반복문이 있는데 그것이 foreach문이다.

string text = "가나다라마";

foreach(char a in text)
{
	print(a);
}

 

이는 문자열을 한글자씩 쪼개준다. 즉 코드를 실행시키면 가, 나, 다, 라, 마가 한글자씩 출력될 것이다.

 


 

아 ~ 힘들다. 별로 한건 없는데 피곤하다. 그렇지만 아직까지는 공부에 대한 열정을 잃지 않았다!

오늘은 조금 길게 게임을 기획하고 아이디어를 내는 시간을 가졌다. 되게 마음에 드는 컨셉이 떠올랐고, 정말로 만들고 싶은 게임이 생겼다.

얼릉 실력을 키워서 정말 나만의 게임을 개발해봐야겠다.

그러기 위해선

달려~~~

'game > unity(C#)' 카테고리의 다른 글

Visual Studio Code 자동 완성이 되지 않는 오류  (0) 2022.07.12
0404) C# 기초 - 3  (0) 2022.04.04
0331) C# 기초 - 1  (0) 2022.03.31
메모장  (0) 2022.03.30
0326(기초 강좌 final)  (0) 2022.03.28
//1. 변수
int x = 100;

//2. 자료형
/*
sbyte 정수 자료형 (-128 ~ +127) - 1바이트
byte 정수 자료형 (0 ~ +255) - 1바이트
short 정수 자료형 (-3만 ~ +3만) - 2바이트
ushort 정수 자료형 (0 ~ +6만) - 2바이트
integer 정수 자료형 (-20억 ~ +20억) - 4바이트
long 정수 자료형 - 8바이트
*/

나는 이때까지 정수 자료형은 integer 밖에 없는 줄 알았는데 int 말고도 몇가지 더 존재 했다.

아마 int가 가장 무난하기 때문에 정수 자료형을 int로 보통 가르쳤지 않나 싶다.

여기서 'long이 가장 범위가 넓으니 정수 자료형을 무조건 long으로 쓰면 좋지 않나?' 라는 생각이 들 수 있다.

하지만 longint로 차지하는 공간의 두배를 차지하기 때문에 나중이 되어서는 굉장히 많은 용량을 잡아 먹을수도 있다.


실수 자료형 또한 float 말고도 다른 자료형들이 존재했다.

//3. 실수 자료형
//float (실수 뒤에 f를 붙여야함)
float f = 4.0000001f;
//double (실수 뒤에 f를 붙이지 않아도 됨)
double d = 4.0000001;
//decimal (실수 뒤에 m을 붙여야함)
decimal m = 4.0000001m;

float보다 double이 오차가 더 작게 발생하며, decimal은 거의 오차가 발생하지 않는다. => 아주 정밀한 계산을 할 때에는 decimal을 사용한다.


//3. 문자 자료형
string s = "asdfwe!13@aㅁㄴ"; // " "
char c = 'A'; //' ', 유니코드(0065) 숫자가 기록됨. 한 글자만 가능.

int a = 100;
string b;
b = a.Tostring(); //강제로 정수를 문자로 변환

강제로 문자를 정수로 변환시키는 함수도 존재한다. int.Parse( )인데, 이러한 강제성을 가지는 것들은 조심해서 써야한다. format이 다를 수 있기 때문이다.


오늘은 내가 가장 힘들어하는 교양 과제를 하다가 영혼이 나간 상태로 몇시간을 허비해버렸다.

그래서 자연스레 내 개인 공부 시간도 줄었다ㅠㅠ..

내일은 목요일로 일주일 중 가장 시간표가 빡세지만,

오늘보다는 조금 더 많이 공부할 것!

+ 게임 기획 idea 시간 가질것

(스포를 하자면 저번 계획 때 3D슈팅 게임 만들 것 같다고 했었는데 그러지 않고 2D로 넘어가 게임을 만들게 될 것 같다. 자세한 이야기는 게임기획서와 함께 찾아오는걸로~)

 

 

'game > unity(C#)' 카테고리의 다른 글

Visual Studio Code 자동 완성이 되지 않는 오류  (0) 2022.07.12
0404) C# 기초 - 3  (0) 2022.04.04
0401) C# 기초 - 2  (0) 2022.04.01
메모장  (0) 2022.03.30
0326(기초 강좌 final)  (0) 2022.03.28
  • C# 파일 제목에서 첫 글자는 대문자로, 뛰어쓰기는 X
  • float 변수 = 숫자f
  • 프로그램이 제대로 실행되지 않을 때는 중괄호 매칭 체크
  • RigidBody 관련 코드는 FixedUpdate에 작성
  • 점프 입력이 원활하게 안되는 문제 발생 => Input 클래스 관련은 Update에 작성
 

 

'game > unity(C#)' 카테고리의 다른 글

Visual Studio Code 자동 완성이 되지 않는 오류  (0) 2022.07.12
0404) C# 기초 - 3  (0) 2022.04.04
0401) C# 기초 - 2  (0) 2022.04.01
0331) C# 기초 - 1  (0) 2022.03.31
0326(기초 강좌 final)  (0) 2022.03.28

+ Recent posts