Project Emerald (Horizontal Scroll Game) - UAVisonline/Portfolio GitHub Wiki

횑슀크둀 μ•‘μ…˜ κ²Œμž„ μ œμž‘

Project EmeraldλŠ” 'λͺ¨λͺ¨λ„라 : 달 μ•„λž˜μ˜ μ§„ν˜Όκ³‘'κ³Ό 같은 횑슀크둀 μ•‘μ…˜κ²Œμž„μ„ λ§Œλ“€κ³ μž ν•˜λŠ” λͺ©μ μœΌλ‘œ μ œμž‘ν•œ Game이닀. ν•΄λ‹Ή Game은 ν”Œλ ˆμ΄μ–΄λ₯Ό μ‘°μ’…ν•΄, 적을 μ—†μ• λ©° 세상을 νƒν—˜ν•˜λŠ” 것을 λͺ©ν‘œλ‘œ μ‚ΌμœΌλ©° μ΄λŸ¬ν•œ 뢀뢄에 μžˆμ–΄μ„œ μ‚¬μš©μžμ˜ 컨트둀 μš”μ†Œλ₯Ό μžκ·Ήν•˜λ„λ‘ μ œμž‘λ˜μ—ˆλ‹€.

ν•΄λ‹Ή ν”„λ‘œμ νŠΈλŠ” 2019λ…„ μ „μ—­ ν›„, μœ λ‹ˆν‹°μ— λ‹€μ‹œ μ μ‘ν•˜κ³ μž μ œμž‘μ„ μ‹œμž‘ν•˜μ˜€λ‹€. λ˜ν•œ ν•„μžμ˜ μ‹€λ ₯에 λΉ„ν•΄ κΈ°νšν•œ κ²Œμž„μ΄ 맀우 λ°©λŒ€ν•˜μ—¬μ„œ μ²΄ν—˜μ΄ κ°€λŠ₯ν•œ μ •λ„λ‘œλ§Œ μ œμž‘ ν›„ μ°¨ν›„ λ‹€μ‹œ μ œμž‘ν•  것을 λͺ©ν‘œλ‘œ ν•˜μ—¬ κ°œλ°œμ„ μ€‘μ§€ν–ˆλ‹€.

ν•΄λ‹Ή ν”„λ‘œμ νŠΈλ₯Ό μ§„ν–‰ν•˜λ©΄μ„œ μ‚¬μš©ν•œ κ·Έλž˜ν”½μ€ 직접 μž„μ‹œλ‘œ μ œμž‘ν•˜μ˜€μœΌλ©°, μ‚¬μš΄λ“œμ™€ 같은 뢀뢄은 freesound.orgμ—μ„œ λ‹€μš΄λ‘œλ“œν•΄ μ‚¬μš©ν•˜μ˜€λ‹€.

ν•΄λ‹Ή ν”„λ‘œμ νŠΈμ— λŒ€ν•œ μœ„ν‚€μ—μ„œλŠ” μ•„λž˜μ™€ 같은 뢀뢄에 λŒ€ν•΄ μ„€λͺ…ν•˜κ³ μž ν•œλ‹€.

  • ν”Œλ ˆμ΄μ–΄ 캐릭터 μ‘°μž‘μ„ μœ„ν•΄ 슀크립트λ₯Ό μ–΄λ–»κ²Œ μž‘μ„±ν•˜μ˜€λŠ”κ°€?
  • 적을 κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄ 슀크립트λ₯Ό μ–΄λ–»κ²Œ μž‘μ„±ν•˜μ˜€λŠ”κ°€?
  • μ§€κΈˆ μ‹œμ μ—μ„œ ν”„λ‘œμ νŠΈμ˜ μ•„μ‰¬μš΄ 뢀뢄은 무엇인가? 이λ₯Ό μ–΄λ–»κ²Œ μˆ˜μ •ν•΄μ•Ό μ’‹μ„κΉŒ?

1. ν”Œλ ˆμ΄μ–΄ 캐릭터 μ‘°μž‘μ— κ΄€ν•˜μ—¬

1.ν”Œλ ˆμ΄μ–΄μ˜ μ›€μ§μž„μ„ μ–΄λ–»κ²Œ μ²˜λ¦¬ν•˜λŠ”κ°€? (PlayerController Script)

ν”Œλ ˆμ΄μ–΄ 캐릭터 μ‘°μž‘μ„ λ‹΄λ‹Ήν•˜λŠ” PlayerController ScriptλŠ” 물리적인 값을 κ°€μ§€λŠ” μ›€μ§μž„μ— λŒ€ν•΄μ„œ λ§€ ν”„λ ˆμž„λ§ˆλ‹€ ν˜ΈμΆœν•˜λŠ” Update ν•¨μˆ˜κ°€ μ•„λ‹Œ 일정 μ‹œκ°„κ°„κ²©λ§ˆλ‹€ ν˜ΈμΆœλ˜λŠ” FixedUpdateλ₯Ό μ‚¬μš©ν•΄ μ²˜λ¦¬ν•˜λ„λ‘ μ§œμ—¬μ Έ μžˆλ‹€.

ν”Œλ ˆμ΄μ–΄ 캐릭터가 λ•… μœ„μ— μžˆμ–΄μ„œ 움직일 수 μžˆμ„λ•Œ, λ•… μœ„μ— μžˆμ§€λ§Œ 곡격을 ν•˜κ³  μžˆμ„ λ•Œ, λ•… μœ„μ— μžˆμ§€μ•Šκ³  λ–¨μ–΄μ§€κ±°λ‚˜, 점프해 올라갈 λ•Œμ™€ 같이 μΊλ¦­ν„°μ˜ 상황에 따라 μ›€μ§μž„ 처리λ₯Ό λ‹€λ₯΄κ²Œ ν•΄μ•Όν•œλ‹€. 이λ₯Ό μœ„ν•΄ ScriptλŠ” μžμ‹ μ˜ ν˜„μž¬ 행동에 λŒ€ν•œ 정보λ₯Ό λ‚˜νƒ€λ‚΄λŠ” 열거체 λ³€μˆ˜ player_stateλ₯Ό κ°€μ§€κ³  있으며, FixedUpdateλŠ” ν•΄λ‹Ή λ³€μˆ˜λ₯Ό 쑰건으둜 μ‚¬μš©ν•΄ ν”Œλ ˆμ΄μ–΄μ˜ μ›€μ§μž„μ„ μ²˜λ¦¬ν•œλ‹€.

85      RaycastHit2D[] hit2D = Physics2D.RaycastAll(transform.position - new Vector3(0.2f, 0.2f, 0.0f), Vector2.right, 0.4f); // 레이캐슀트λ₯Ό ν†΅ν•œ μ§€μƒκ³Όμ˜ 좩돌 체크
        bool ground = false;
        foreach(var hit in hit2D)
        {
            if(hit.collider.CompareTag("Ground"))
            {
                ground = true;
                break;
            }
        }

        if (ground) // ν”Œλ ˆμ΄μ–΄κ°€ 땅에 μžˆλŠ” 경우
        {
                Can_Jump = true;
                if(!Input.GetKey(KeyCode.D)) // 점프킀 μž…λ ₯ 쀑이 μ•„λ‹Œ 경우
                {
                    up_time = 0.0f; // 점프 μ‹œκ°„ 0으둜 μ΄ˆκΈ°ν™”
                }
        }
        else if (rb.velocity.y < 0.0f && !ground) // κ³΅μ€‘μ—μ„œ λ–¨μ–΄μ§€λŠ” 쀑
        {
            Can_Jump = false;
            up_time = up_time_limit + 0.1f; // ν˜„μž¬ μ ν”„ν•˜λŠ” μ‹œκ°„ 값을 λ°”κΏ” κ°•μ œλ‘œ μ ν”„λΆˆκ°€λŠ₯으둜 ꡐ체
108     }

μš°μ„  PlayerController Script의 85번째 쀄뢀터 108번째 쀄은 캐릭터가 λ•… μœ„μ— μ„œμžˆλŠ”μ§€ κ·Έλ ‡μ§€ μ•Šμ€μ§€ ν™•μΈν•˜κ³ , κ·Έ μƒνƒœμ— 따라 점프 κ΄€λ ¨ λ³€μˆ˜λ₯Ό 바꾸도둝 ν•˜κ³  μžˆλ‹€. 이λ₯Ό μœ„ν•΄ 캐릭터 μ•„λž˜μ— λŒ€ν•΄ raycastλ₯Ό 쏘고 Ground Tagλ₯Ό κ°€μ§„ μ˜€λΈŒμ νŠΈκ°€ κ²€μΆœλ˜λŠ”μ§€ 확인, 이에 따라 ground λ³€μˆ˜μ˜ 값을 λ³€κ²½ν•œλ‹€.

κ·Έ λ’€ λ•… μœ„μ— μžˆμœΌλ©΄μ„œ ν˜„μž¬ 점프 ν‚€λ₯Ό λˆ„λ₯΄μ§€ μ•ŠμœΌλ©΄ 점프 μ‹œκ°„μ„ 0으둜 μ΄ˆκΈ°ν™”ν•΄ 점프λ₯Ό λˆ„λ₯΄λ©΄ κ·Έ μ‹œκ°„μ„ 잘 λ°˜μ˜ν•  수 μžˆλ„λ‘ μ„€μ •ν•˜λ©°, λ•… μœ„μ— μžˆμ§€ μ•ŠμœΌλ©΄μ„œ λ–¨μ–΄μ§€λŠ” κ²½μš°μ—λŠ” 점프 μ‹œκ°„μ˜ 값을 크게 μ„€μ •ν•΄ 점프가 λ˜μ§€ μ•Šλ„λ‘ μ„€μ •ν•˜μ˜€λ‹€.

110     if (player_state == current_State.S_standing || player_state == current_State.S_running || player_state == current_State.S_jumping || player_state == current_State.S_jumpswording) // μ„œμžˆκ±°λ‚˜, λ›°κ±°λ‚˜, μ ν”„ν•˜κ±°λ‚˜, 점프 κ³΅κ²©μ€‘μ΄κ±°λ‚˜
        {
            if (Can_move) // 움직일 수 있으면
            {
                .....(이동 및 μ’Œμš°λ°˜μ „ κ΄€λ ¨)

                if (Can_Jump) // 점프 κ°€λŠ₯ν•  λ•Œ
                {
                    ...... (ν”Œλ ˆμ΄μ–΄ μœ„μ— 땅이 μ‘΄μž¬ν•˜λŠ”μ§€, μ•„λ‹Œμ§€ Raycastλ₯Ό μ΄μš©ν•΄ 확인)

                    if(!not_up && ready_time<=0.0f && rb.mass>=1.0f) // μœ„κ°€ λΉ„μ–΄μžˆμœΌλ©΄μ„œ ν”Œλ ˆμ΄μ–΄ μ§ˆλŸ‰μ΄ 1.0μ΄μƒμ΄λ©΄μ„œ μ€€λΉ„μ‹œκ°„μ΄ 0.0 μ΄ν•˜μ΄λ©΄
                    {
                        if (Input.GetKey(KeyCode.D))
                        {
                            if (up_time < up_time_limit) // ν˜„μž¬ 점프 μ‹œκ°„μ΄ μ œν•œμ‹œκ°„μ„ λ„˜μ§€ μ•Šμ€ κ²½μš°μ— λŒ€ν•΄
                            {
145~158                       .....(점프 처리 κ΄€λ ¨)
                            }
                        }
                    } 
                }
            }
        }
166     player_animator.SetBool("Can_jump", ground); // μ ν”„μ• λ‹ˆλ©”μ΄μ…˜μ„ μžμ—°μŠ€λŸ½κ²Œ λ§Œλ“€μ–΄μ€Œ
    }

μΊλ¦­ν„°μ˜ 행동 상 μ›€μ§μž„ 값을 가져도 상관 μ—†λŠ” κ²½μš°μ— λŒ€ν•΄ 110번째 쀄과 같이 player_state λ³€μˆ˜λ₯Ό 쑰건으둜 이용, μΊλ¦­ν„°μ˜ 행동을 읽으며 μ›€μ§μž„μ— λŒ€ν•œ 뢀뢄을 μ²˜λ¦¬ν•˜λ„λ‘ ν•œλ‹€. μ΄λŸ¬ν•œ 처리 λ‚΄μš©μœΌλ‘œλŠ” 크게 캐릭터 이동(Run ν•¨μˆ˜), 캐릭터 점프(145~158 Line)이 μ‘΄μž¬ν•˜λ©°, μ—¬κΈ°μ—μ„œλ„ player_stateλ₯Ό μ΄μš©ν•΄ ν•΄λ‹Ή 뢀뢄에 μžˆμ–΄μ„œ 세뢀적인 처리 (Runν•¨μˆ˜ λ‚΄ 점프곡격과 κ·Έλ ‡μ§€ μ•Šμ€ 경우λ₯Ό λΆ„λ¦¬ν•œ λΆ€λΆ„)κ°€ κ°€λŠ₯ν•˜λ‹€.


2. μ›€μ§μž„μ„ μ œμ™Έν•œ 행동(곡격 및 μ•„μ΄ν…œμ‚¬μš©)은 μ–΄λ–»κ²Œ μ²˜λ¦¬ν•˜λŠ”κ°€? (PlayerController Script)

ν”Œλ ˆμ΄μ–΄ μΊλ¦­ν„°μ˜ 곡격 및 μ•„μ΄ν…œμ‚¬μš©κ³Ό 같은 뢀뢄은 Update ν•¨μˆ˜λ₯Ό 톡해 μ²˜λ¦¬ν•˜λ©° μ—¬κΈ°μ—λŠ” ν”Œλ ˆμ΄μ–΄μ˜ λ¬΄μ μ‹œκ°„, 행동 μΏ¨νƒ€μž„κ³Ό 같은 μ‹œκ°„ 값도 Time.deltaTime을 μ΄μš©ν•΄ μ²˜λ¦¬ν•˜κ³  μžˆλ‹€. λ˜ν•œ Update λ‚΄ 행동 μ²˜λ¦¬λ„ FixedUpdate λ‚΄ μ›€μ§μž„ μ²˜λ¦¬μ™€ 같이 player_stateλ₯Ό 톡해 ν˜„μž¬ ν”Œλ ˆμ΄μ–΄μ˜ 행동을 읽고, 이λ₯Ό 쑰건으둜 μ‚Όμ•„ ν•  수 μžˆλŠ” 행동을 μ •ν•΄μ£ΌλŠ” λ°©μ‹μœΌλ‘œ λ™μž‘ν•œλ‹€.

200     if (player_state == current_State.S_standing || player_state == current_State.S_running) // λ›°κ±°λ‚˜ μ„œμžˆμœΌλ©΄
        {
            if(ready_time>0.0f) // μ€€λΉ„ μ‹œκ°„μ΄ 있으면 (λ‹€λ₯Έ μ „νˆ¬ 행동을 ν•  수 μ—†μŒ)
            {
                ready_time -= Time.deltaTime;
            }
            if(ready_time<=0.0f) // μ€€λΉ„ μ‹œκ°„μ΄ μ—†μœΌλ©΄
            {
                  ...(μ»€λ§¨λ“œ μž…λ ₯에 λ”°λ₯Έ ν–‰λ™μ²˜λ¦¬ - Battle_Action ν•¨μˆ˜ 호좜)
            }
            if (Input.GetKeyDown(KeyCode.Space)) // 점멸
            {
                if (Rolling == false)
                {
                    Battle_Action("Roll");
                }
            }
        }

μ˜ˆμ‹œλ‘œ Updateλ‚΄ μœ„ μ½”λ“œμ™€ 같이 player_stateκ°€ standing, runningμ΄λ©΄μ„œ 캐릭터가 행동을 ν†΅ν•œ μΏ¨νƒ€μž„μ΄ μ—†μœΌλ©΄ μ»€λ§¨λ“œμ— 따라 string 인자λ₯Ό κ°€μ§€λŠ” Battle_Action ν•¨μˆ˜λ₯Ό 호좜, player_state의 μƒνƒœ 및 Animator용 λ³€μˆ˜λ₯Ό λ³€κ²½ν•œλ‹€. 그리고 이λ₯Ό 톡해 AnimatorλŠ” ν”Œλ ˆμ΄μ–΄μ˜ 행동 λ³€ν™”λ₯Ό animation으둜 μ§„ν–‰, animation_eventλ₯Ό 톡해 μƒμ„Έν•œλ³€ν™”λ₯Ό μ‹€μ œλ‘œ κ΅¬μΆ•ν•œλ‹€.

BGM Game

2. 적을 κ΅¬ν˜„ν•˜κΈ° μœ„ν•˜μ—¬

1.λΆ€λͺ¨ 슀크립트λ₯Ό ν†΅ν•œ ν‹€ λ§Œλ“€κΈ° (Enemy Script and Detect_zone Script)

κ΅¬ν˜„ν•΄μ•Ό ν•˜λŠ” 적듀은 체λ ₯ 및 ν”Œλ ˆμ΄μ–΄ 탐지, κ³΅κ²©λ°›μŒ, 넉백과 같은 κ³΅ν†΅μ μœΌλ‘œ κ³΅μœ ν•˜λŠ” κΈ°λŠ₯이 μ‘΄μž¬ν•œλ‹€. λ”°λΌμ„œ 이λ₯Ό μœ„ν•΄ λͺ¨λ“  적 κ°œμ²΄λ“€μ΄ 상속받을 λΆ€λͺ¨ Scriptλ₯Ό λ§Œλ“€μ–΄μ•Ό ν•˜λ©°, 이λ₯Ό Enemy Script와 같은 ν˜•νƒœλ‘œ κ΅¬ν˜„ν•œλ‹€.

ν•΄λ‹Ή μŠ€ν¬λ¦½νŠΈμ—λŠ” μœ„μ—μ„œ λ§ν•œ 뢀뢄을 μ²˜λ¦¬ν•˜κ³ μž 각 κΈ°λŠ₯을 ν•¨μˆ˜(Damaged_bullet, Damaged_sword, Knockback, detect) 및 λ³€μˆ˜(detection, hp)둜 κ΅¬ν˜„ν–ˆλ‹€.
λ˜ν•œ μ λ“€μ€‘μ—μ„œλ„ 크기가 큰 개체, μž‘μ€ 개체, 원거리곡격에 λŒ€ν•΄ 무적인 개체 λ“± λ‹€μ–‘ν•œ μ’…λ₯˜μ˜ κ°œμ²΄κ°€ 있으며 이에 λŒ€ν•œ μ΄νŽ™νŠΈ 처리λ₯Ό ν•΄μ•Όν•˜λ―€λ‘œ 이λ₯Ό μœ„ν•œ λ³€μˆ˜(size_big, size_small)λ₯Ό μ„€μ •, ν•¨μˆ˜μ—μ„œλŠ” ν•„μš”μ— 따라 이λ₯Ό μ‚¬μš©ν•˜λ„λ‘ ν•œλ‹€.

λ˜ν•œ 적의 탐지 μƒνƒœλ„ ν”Œλ ˆμ΄μ–΄λ₯Ό μ™„μ „νžˆ νƒμ§€ν–ˆλŠλƒ, νƒμ§€ν–ˆλŠ”λ° μœ„μΉ˜λ₯Ό λͺ¨λ₯΄λƒ, νƒμ§€ν–ˆκ³  μœ„μΉ˜λ„ μ•Œκ³  μžˆλŠλƒμ— 따라 행동이 달라져야 ν•œλ‹€. 이λ₯Ό μœ„ν•œ λ³€μˆ˜ follow_time, detect_time을 μ„€μ •ν•˜λ©°, λ³€μˆ˜μ˜ μš°μ„ μˆœμœ„μ— 따라 값이 κ°μ†Œν•˜λ„λ‘ Updateμ½”λ“œλ₯Ό μ§ λ‹€.

λ˜ν•œ 탐지λ₯Ό ν–ˆλŠ”λ° μœ„μΉ˜λ₯Ό λͺ¨λ₯΄λ©΄ νƒμ§€λ°˜κ²½μ΄ λ„“μ–΄μ Έμ•Ό ν•˜λ―€λ‘œ 이λ₯Ό μœ„ν•œ λ²”μœ„ DetectZone을 μ„€μ •, 이λ₯Ό μœ„ν•œ Detect Zone을 μž‘μ„±ν•˜μ˜€λ‹€. ν•΄λ‹Ή ScriptλŠ” Collider λ‚΄ ν”Œλ ˆμ΄μ–΄κ°€ μ ‘κ·Όν•˜λ©΄ Enemy Script의 Detectν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•˜μ—¬μ„œ 적이 λ‹€μ‹œ ν”Œλ ˆμ΄μ–΄λ₯Ό νƒμ§€ν•˜λ„λ‘ λ§Œλ“œλŠ” μž‘μ—…μ„ μ‹€ν–‰ν•œλ‹€.

μœ„ Enemy Scriptλ₯Ό 톡해 틀을 λ§Œλ“€μ—ˆμœΌλ©΄ Grunt_Swordman, Grunt_Archer와 같이 이λ₯Ό 상속받은 Scriptλ₯Ό μž‘μ„±, μƒμ„Έν•œ 행동을 μ„€μ •ν•˜λŠ” 것(Raycastλ₯Ό ν†΅ν•œ κ³΅κ²©λ²”μœ„ 및 곡쀑에 λ– μžˆλŠ”μ§€ 확인, Animator μ„€μ •)으둜 μ‹€μ œ 적 였브젝트λ₯Ό κ²Œμž„ λ‚΄μ—μ„œ κ΅¬ν˜„ν•  수 μžˆλ‹€.

BGM Game

3. μ§€κΈˆ μ‹œμ μ—μ„œ ν”„λ‘œμ νŠΈμ˜ μ•„μ‰¬μš΄ 뢀뢄은 어디라고 μƒκ°ν•˜λŠ”κ°€? 이λ₯Ό μ–΄λ–»κ²Œ μˆ˜μ •ν•΄μ•Ό μ’‹μ„κΉŒ?

μ½”λ“œ λ‚΄ 좩돌과 κ΄€λ ¨λœ λΆ€λΆ„μ—μ„œ Raycast듀은 Raycastall을 μ΄μš©ν•΄ λ™μž‘ν•˜κ³  μžˆλ‹€. κ·ΈλŸ¬λ‚˜ RaycastAll은 λΆ€λ”ͺ힌 λͺ¨λ“  였브젝트λ₯Ό κ²€μΆœν•˜κ³  있으며, 였브젝트 μˆ˜κ°€ λ§Žμ„μˆ˜λ‘ μ—°μ‚°λŸ‰μ΄ λ§Žμ•„μ§„λ‹€.

λ”°λΌμ„œ 이λ₯Ό λ§‰κΈ°μœ„ν•΄ 각 μ˜€λΈŒμ νŠΈλ§ˆλ‹€ Tagκ°€ μ•„λ‹Œ Layerλ₯Ό μ„€μ •ν•˜λ©° 이λ₯Ό Raycast μΆ©λŒμ— λŒ€ν•œ 쑰건으둜 μ£ΌλŠ” λ°©μ‹μœΌλ‘œ μˆ˜μ •ν•œλ‹€λ©΄, 연산뢀뢄에 μžˆμ–΄μ„œ 큰 이득을 얻을 수 μžˆμ„ 것이닀.

⚠️ **GitHub.com Fallback** ⚠️