본문 바로가기

TIL

[TIL]2024-2-15 / 37일차 - 팀 과제 4일차

 

1. 오늘의 알고리즘 코드카타 - 시저 암호

 

답안 :

//이번에는 어느정도 구조는 생각이 나지만
//그걸 구현하는 방법을 모르겠어서 찾아보니 아스키 코드로 푸는 방법도 있었다.
using System;

public class Solution {
    public string solution(string s, int n) {
        string answer = "";

        //문자열을 우선 char 배열로 저장
        char[] arr = s.ToCharArray();
        
        for(int i = 0; i < arr.Length; ++i)
        {
            //공백은 공백으로 남겨야함
            if(arr[i] == ' ')
                continue;
            
            //n만큼 문자를 밀어내기
            int num = Convert.ToInt32(arr[i]) + n;
        
            //대문자를 밀어낼 때 순서 상 소문자 영역으로 밀려나기도 함
            //이를 방지하기 위한 조건문 필요
            //원본 문자를 확인하여 소문자인지 대문자인지 체크하는 조건문
        
            if((arr[i]) >= 'A' && arr[i] <= 'Z')
            {
                if(num > 'Z')
                    num -= 26;
            }
            else
            {
                if(num > 'z')
                    num -= 26;
            }
            arr[i] = Convert.ToChar(num);
        }
        
        answer = new string(arr);
        
        return answer;
    }
}

 


2. 오늘의 작업

정말 너무 너무 너무 피곤해서 적당히 적어두겠다.

 

개별 로직들로 구현 된 무기들 - 아예 다른 작동 방식

 

각 무기들은 플레이어 스텟 매니저에서 전달받은 스텟을 이용해

플레이어 어택 컨트롤러에서 플레이어 스탯의 공격속도를 체크하여 공격 메서드를 발동 시키면

어택 매니저에서 공격들의 실행 정보를 가지고

무기 인터페이스로 만든 각각 등록된 웨폰들 중 장착된 웨폰의 어택 메서드가 실행되며

이렇게 발사 로직이 실행되면 그 로직으로 생성된 불렛이

고유의 불렛 로직으로 각기 다른 공격 방법을 가진다.

 

 

 

 

위의 파이어볼은

WeaponNormal에서 발사를 다루며 (기본 공격이기 때문에 이름이 노멀이다)

bullet_Fireball이 발사체의 로직을 다룬다

발사체의 로직에는 평범한 투사체 발사 기능에 더해

플레이어 스탯에 있는 관통 수치를 받아 적을 관통한다.

적을 관통하는 방법은 다음을 이용했다.

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.gameObject.layer == LayerMask.NameToLayer("Level"))
        {
            isHit = true;
        }

        if (targetLayer == (targetLayer | (1 << collision.gameObject.layer)))
        {
            //최근 맞춘 적 관통할 때 중복 충돌을 체크하기 위함
            //체력감소            
            HealthSystem healthSystem = collision.GetComponentInParent<HealthSystem>();
            if (healthSystem != null)
            {
                if (healthSystem != recentlyHitEnemey)
                {
                    healthSystem.ChangeHealth(-Atk);
                    pCount--;
                    Debug.Log("관통");
                    recentlyHitEnemey = healthSystem;
                    if(pCount > 0)
                    {
                        SoundManager.Instance.PlayClip(pierceClip);
                    }
                }

                if (pCount == 0)
                {
                    Debug.Log("관통 종료");
                    isHit = true;
                }
            }          
        }

        if (isHit)
        {
            SoundManager.Instance.PlayClip(explodeClip);
            animator.SetTrigger("Explode");
        }
    }

 

적의 콜라이더에 닿을 때 마다 관통 카운트가 줄어들고 관통 카운트가 0이 되는 순간에는 isHit이 true가 되어 폭발하며 사라진다.

 

한번 체크 된 적에게서 다시 관통이 되는 상황을 막기 위해 방금 닿은 적의 헬스 시스템 컴퍼넌트를 저장하고

다시 체크 된 콜라이더에 헬스 시스템이 같은 개체인지 비교하는 방법을 이용했다.

 

그리고 Weapon에는 발사체 갯수와, 발사체가 늘어나면 발사 각도 만큼 발사 각이 틀어지는 구현을 해야했다.

 

이를 여러 방법으로 시도해 보다가 완성된 코드는 다음과 같다.

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

public class WeaponNormal : IWeapon
{
    public void Attack(PlayerStatManager playerStat, Vector2 origin, Vector2 dir)
    {
        float initialAngle = -15f * (playerStat.A_AddBullet / 2f);

        if(playerStat.A_AddBullet == 0)
        {
            // 한 발만 발사할 때
            Bullet_Fireball onefireball = Managers.RM.Instantiate("Projectiles/Bullet_Fireball").GetComponent<Bullet_Fireball>();
            onefireball.Setup(origin, dir, playerStat.A_Atk, playerStat.W_BulletSpeed, playerStat.W_Duration, playerStat.A_PierceCount);
        }
        

        // 한 발 이상 발사
        for (int i = 0; i <= playerStat.A_AddBullet; i++)
        {
            // 투사체 간 거리 각도 계산
            float angle = initialAngle + i * 15f;

            // 회전된 방향으로 투사체를 생성합니다.
            Vector2 newDir = RotateVector2(dir, angle);
            Bullet_Fireball fireball = Managers.RM.Instantiate("Projectiles/Bullet_Fireball").GetComponent<Bullet_Fireball>();
            fireball.Setup(origin, newDir, playerStat.A_Atk, playerStat.W_BulletSpeed, playerStat.W_Duration, playerStat.A_PierceCount);
        }
    }

    // 벡터를 회전하는 메서드입니다.
    private static Vector2 RotateVector2(Vector2 v, float degree)
    {
        return Quaternion.Euler(0, 0, degree) * v;
    }
}

 

한 발만 발사를 할 때는 곧게 나갈 수 있어야 하기 때문에 한 발을 발사할 때와 그 이상일 때를 구분 했다.

 

 

 

다른 무기인 번개 무기의 경우 오히려 더 간단한 로직을 가지고 있다.

 

우선 WeaponThunder에서 발사 로직을 다루고

Bullet_Thunder에서 발사체의 로직을 다루는데

 

발사체의 경우에는 날아갈 필요도 없고 관통이 필요 없어 오히려 간단해졌다.

 

발사체는 생성된 순간에는 낙뢰가 떨어지기 이전이기 때문에 우선 콜라이더가 꺼져 있어야 하고

내려치는 순간 콜라이더가 켜지며 적에게 데미지를 주어야 한다.

 

이를 단순하게 애니메이션 이벤트를 통해 타이밍을 조절하여 쉽게 해결했다.

 

WeaponThunder의 경우

파이어볼과는 다르게 발사체 갯수가 늘어나면 같은 곳에 여러 번 내려치는 것이 아닌

 

기존 위치에 더해서 랜덤한 위치에 더 떨어지도록 기획했다.

이를 구현하기 위해 for문으로 추가 발사체 갯수만큼 i를 돌려

처음 한 발은 그대로 떨어지되 (i = 0일 때)

다음 부터는 랜덤 좌표 값을 받아 새로 입력된 값으로 발사체를 생성했다. 이는 다음과 같다.

 

using UnityEngine;
using System.Collections;

public class WeaponThunder : IWeapon
{
    public void Attack(PlayerStatManager playerStat, Vector2 origin, Vector2 dir)
    {
        for (int i = 0; i <= playerStat.A_AddBullet; i++)
        {
            Vector2 newOrigin = origin;
            if (i > 0)
            {
                // 랜덤한 범위 내에서 위치를 변경
                float offsetX = Random.Range(-4f, 4f);
                float offsetY = Random.Range(-4f, 4f);
                newOrigin += new Vector2(offsetX, offsetY);
            }

            Bullet_Thunder thunder = Managers.RM.Instantiate("Projectiles/Bullet_Thunder").GetComponent<Bullet_Thunder>();
            thunder.Setup(newOrigin, dir, playerStat.A_Atk, playerStat.W_BulletSpeed, playerStat.W_Duration, playerStat.A_PierceCount);
        }
    }
}

 

이 외에도 각종 완성도를 위한 간단한 애니메이션, 사운드 작업과 아트 에셋을 준비했고

 

 

이런 피격 모션과 데스 모션

 

거기에 재미 삼아서 프로젝트의 타이틀 로고도 만들었다.

 

두근 두근 문예부의 패러디인 두근 두근 내배캠이기 때문에

원본 게임의 로고를 이용해 조잡하게 변형했다.

 

 

그리고 이전에 작성했던 투사체 발사 방향 문제 해결 과정을 발표 자료용 트러블 슈팅 영상으로 만들었다.

 

 

 

 

사실 이번 과제에서는 다른 실력 있는 팀원들 덕분에

온 갓 매니저와 컨트롤러, 자동화 작업들이 이루어졌기 때문에 짧은 시간이지만 이 정도로 완성도 좋은 팀 과제는 처음이었다. 사실 다른 팀의 코드들이 뛰어나다 한들, 지금처럼 내가 그것에 참여하고 설명을 들어보고 같이 이용해본 코드와는 이해도가 차원이 다르기에 공부가 힘들었다.

 

그렇기 때문에 과제가 끝나더라도 나중에 찾아와서 공부할 수 있을 자료가 될 것 같다.