01/29 본캠프 #25

guno park·2024년 1월 29일
0

본캠프

목록 보기
25/77

알고리즘 풀어보기

예상 대진표

내가 한 풀이

using System;

class Solution
{
    public int solution(int n, int a, int b)
    {
        int answer = 1;
        a+=-1;
        b+=-1;
        while(MathF.Abs(a-b)!=1){
            answer++;
            a/=2;
            b/=2;
        }
        return answer;
    }
}

간단하게 생각하고 진행했는데 이게 아니더라, 이렇게 하면 다른 조로 편성되지만 딱 붙어 있는 경우에 조건을 만족한걸로 취급하고 바로 종료되어버린다.
반례

참고한 풀이

딱히 좋은 생각은 안 나는데 미완으로 넘기긴 싫고 팀 과제도 바빠서 후딱 찾아보았다.
참고자료

using System;
class Solution
{
    public int solution(int n, int a, int b)
    {
        int answer =1;
        for(int i=0; i<n/2;i++)
        {   
            if((a%2==0&&a-1==b)||(a%2!=0&&a+1==b)) break;
            if(a%2==0)      a=a/2;
            else            a=(a+1)/2;
            if(b%2==0)      b=b/2;
            else            b=(b+1)/2;
            answer++;
        }
        return answer;
    }
}

위 코드를 분석하자면, 만약 같은 조에 있다면 이미 만난 것으로 바로 break;
그게 아니라면 나머지 유무에 따라 2로 나눠서 다시 조편성에 들어가는 것을 반복한다.
맨 윗줄의 같은 조에 있는 지 여부를 판단하는 것이 주요하게 작용한다.

팀 프로젝트

폭탄병 파티클 추가

폭탄병이 터질 때 너무 밋밋한 것 같아서 파티클을 추가했다.

원으로 해서 네모 스프라이트를 라이프타임에 맞춰 색을 바꿔주는 방식으로 했고,
기존에 기폭되는 코루틴 안에 대기시간을 두어 작동시간이 끝나면 다시 끄도록 작성했다.
재사용 시에 또 켜져야하기 때문에

 IEnumerator Getbomb()
    {    
        var shapeModule = _particleSystem.shape;
        shapeModule.radius = explosionRad; //폭팔 반경에 맞춰 파티클의 크기도 바뀜.
        yield return new WaitForSeconds(1f);
        
        Particle.SetActive(true);
        yield return new WaitForSeconds(1f);
        
        Particle.SetActive(false);
        _healthSystem.CallDeath();
        
    }

몬스터 페이드 아웃 적용하기 + 초기화하기

페이드아웃하기

어제 만든 페이드 아웃 기능을 몬스터들에게 적용해 줄 시간이다.
이미 몬스터들의 체력 시스템에 OnDeath가 존재하기 때문에, 이벤트 구독만 시켜놓으면 알아서 된다. 그것 또한 Monster_Disapear 스크립트에 존재한다.

몬스터들의 무적시간을 삭제하고, 스크립트를 넣어주었다.

이렇게 해두면 체력이 0이 되면 알아서 페이드아웃되며 사라진다.
추가로 땅에 붙이면서 그래비티 스케일도 켜두었기 때문에 사망 시 맵 밑으로 떨어지는 연출도 된다.

초기화하기

몬스터가 죽으면 발생하는 die 메서드는 몬스터의 스프라이트 알파값이 0이 되는 페이드 아웃 이외에도, 모든 컴포넌트를 비활성화 시키는 메서드도 포함되어있다.

이 프로젝트에서는 오브젝트 풀링으로 몬스터를 재사용하기 때문에 몬스터가 소환될 때 스프라이트의 알파값과 모든 컴포넌트를 원상태로 돌리고, 체력 또한 복구해주어야 한다.

 public void initiallize()
    {
        if (!isFirst)
        {
            ready = false;
        
            foreach (SpriteRenderer renderer in transform.GetComponentsInChildren<SpriteRenderer>())
            {
                Color newColor = new Color(renderer.color.r, renderer.color.g, renderer.color.b, 255);
                renderer.color = newColor;   
            }
        
            foreach (Behaviour component in transform.GetComponentsInChildren<Behaviour>())
            {
                component.enabled = true;
            }
        
            _healthSystem.InitializeHealth();
        }
    }

몬스터 한 종류의 초기화 예시로, isfirst라는 조건을 걸어 맨 처음 생성될 때는 초기화하지 않고, 그 이후부터 초기화하도록 만들었다. 그리고 현재 체력의 경우 set은 외부 접근이 불가능하기 때문에 같은 스크립트에서 처리할 수 있도록 메서드로 초기화 해주었다.

씬 병합하기

오류 수정

  • 원거리 공격 프리팹이 나오지 않음. => 프로젝틸 매니저 수정 후 복구

  • 플레이어가 공격을 안 맞음. => 플레이어에 헬스시스템 없었음.

  • 원거리 몬스터들이 공격을 받지 않음.

    원인 : 근거리 몬스터들은 콜라이더를 2개 가지고 있어서 모든 콜라이더에 대한 충돌처리가 가능했지만, 원거리 몬스터들은 콜라이더가 하나로, 그 콜라이더는 플레이어와 벽에만 충돌처리가 가능하도록 Layer overrides가 설정되어 있었음.

    해결방법 : 플레이어가 발사하는 투사체에도 레이어를 추가하고, 이 레이어를 몬스터들이 처리할 수 있도록 설정해주었음.

지상 몬스터 땅으로 다니게 하기

방법 1 : 그래비티 스케일 쎄게 주기
방법 2 : 이동 방식 바꾸기

당연하게도 2번을 선택했다.

기존에는 Movement.cs 한 개의 스크립트로 모두 처리했지만 땅에 붙어 다니게 하기위해서 플레이어의 Movement와 별개의 몬스터 전용 이동 스크립트를 만들었다.
이 스크립트에서 지상 몬스터들은 몬스터-플레이어의 방향인 direction에서 x축 값만 사용해 이동하게 된다.

void Move(Vector2 direction)
    {
        _moventDirection = new Vector2(direction.x,0);
    }

    void ApplyMovent(Vector2 direction)
    {
        direction = direction * _monsterStatsHandler.CurrentStates.speed;
        if(knockbackDuration > 0)
        {
            direction += _knockback;
        }
        _rigidbody.velocity = direction;
    }

몬스터 스폰위치 변경하기

똥피하기 + 몬스터 디펜스 같은 게임이며 플레이어가 이동을 자주하기 때문에 몬스터의 스폰위치를 고정시키는 것보다 플레이어의 위치에 맞춰 이동하는 것이 좋다고 생각했다.

 private void MoveSpawnPosition()
    {
        _playerPos = _gameManager.player.transform;
        groundSpawnPoint[0].transform.position = new Vector3(_playerPos.position.x-20,-3.4f,0f);
        groundSpawnPoint[1].transform.position = new Vector3(_playerPos.position.x+20,-3.4f,0f);
        skySpawnPoint[0].transform.position = new Vector3(_playerPos.position.x, 13f, 0);
        skyRallyPoint[0].transform.position = new Vector3(_playerPos.position.x-10,5f,0f);
        skyRallyPoint[1].transform.position = new Vector3(_playerPos.position.x+10,5f,0f);
    }

각 스폰위치마다 플레이어를 기준으로 하여 일정한 위치를 가지도록 update에서 실행 가능한 메서드로 만들었다.

개인과제 피드백

  1. 다운로드한 에셋들은 폴더 구분으로 정리할 것.

  2. 새롭게 생성된 오브젝트들은 Transform을 초기화 할 것 (내가 보는 지점에 생성되기 때문에)

  1. Canvas를 구분하여 사용하기 보다는 Canvas 하위의 오브젝트로 구분해서 쓰시면 좋습니다.
    (Canvas의 크기가 같다면? 이라는 전제가 있는 거 같긴 하다.)
  1. Animation 같이 유니티에서 사용하는 클래스 명칭을 사용하시면 안됩니다
  1. 취향에 따라 달라질수 있지만 메서드명을 너무 함축 시키면 다른분들과 협업하기 어려울수 있으니 적당히 풀어주세요.
  1. #region 구분하여 사용하신건 깔끔하게 잘 사용하셨습니다.
    너무 세분화 하시지는 마시고 큰 분류를 어떻게 할지 생각하시고 사용하시면 좋을것 같아요
    => 캐릭터1 캐릭터2 이렇게 다 하지말고 캐릭터1~~~캐릭터4 이렇게 한묶음.

게임 분석해보기

게임을 해보고 싶어서도 있지만, 기왕 할꺼면 분석하면서 해보자는 취지의 시간

산나비 - 기계지렁이까지

게임 시스템 관련

  • 이동방식
    점프 이동이나 역방향 이동을 할 때 묘한 가속도가 느껴진다.
    아마도 rigidbody2D.velocity가 아닐까?

  • 마우스로 적을 타게팅 하는 게임인데, 에임 보정으로 자칫 어려울 수 있는 부분들을 보완하여 화려하고 속도감 있는 게임이 되었다.

  • 기계가 불타며 연기가 올라오는 연출에서 연기는 파티클(?) 같은 걸로 하고, 안에서 스프라이트가 애니메이션으로 움직이며 Z축 회전하며 하늘로 올라가고 있었다.

연출 관련

  • 튜토리얼 초반에 화면 산딸기 대원이 있는 위치까지 카메라가 이동하는 연출이 좋다.
    배경들이 러프하게 그려지면서 속도감을 준다.

  • 음악도 좋아하는 타입의 음악인데, 극 중 진행에 따라 절묘하게 볼륨이 줄어들어 스토리에 집중할 수 있도록 해준다.

  • 튜토리얼 부분을 너무 평온하고 가정적으로 잘 만들어서 반전이 더 크게 다가온다.
    주인공이 천당에서 수직낙하로 지옥에서 내다꽂히는 게 느껴진다.

  • 스토리 플롯은 영화와 비슷하게 진행되는 느낌을 받았다.
    ex : 고집불통 남주인공과 어떻게든 따라가려고 설득하는 여주인공

0개의 댓글