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에서 실행 가능한 메서드로 만들었다.
다운로드한 에셋들은 폴더 구분으로 정리할 것.
새롭게 생성된 오브젝트들은 Transform을 초기화 할 것 (내가 보는 지점에 생성되기 때문에)
- Canvas를 구분하여 사용하기 보다는 Canvas 하위의 오브젝트로 구분해서 쓰시면 좋습니다.
(Canvas의 크기가 같다면? 이라는 전제가 있는 거 같긴 하다.)
- Animation 같이 유니티에서 사용하는 클래스 명칭을 사용하시면 안됩니다
- 취향에 따라 달라질수 있지만 메서드명을 너무 함축 시키면 다른분들과 협업하기 어려울수 있으니 적당히 풀어주세요.
게임을 해보고 싶어서도 있지만, 기왕 할꺼면 분석하면서 해보자는 취지의 시간
이동방식
점프 이동이나 역방향 이동을 할 때 묘한 가속도가 느껴진다.
아마도 rigidbody2D.velocity가 아닐까?
마우스로 적을 타게팅 하는 게임인데, 에임 보정으로 자칫 어려울 수 있는 부분들을 보완하여 화려하고 속도감 있는 게임이 되었다.
기계가 불타며 연기가 올라오는 연출에서 연기는 파티클(?) 같은 걸로 하고, 안에서 스프라이트가 애니메이션으로 움직이며 Z축 회전하며 하늘로 올라가고 있었다.
튜토리얼 초반에 화면 산딸기 대원이 있는 위치까지 카메라가 이동하는 연출이 좋다.
배경들이 러프하게 그려지면서 속도감을 준다.
음악도 좋아하는 타입의 음악인데, 극 중 진행에 따라 절묘하게 볼륨이 줄어들어 스토리에 집중할 수 있도록 해준다.
튜토리얼 부분을 너무 평온하고 가정적으로 잘 만들어서 반전이 더 크게 다가온다.
주인공이 천당에서 수직낙하로 지옥에서 내다꽂히는 게 느껴진다.
스토리 플롯은 영화와 비슷하게 진행되는 느낌을 받았다.
ex : 고집불통 남주인공과 어떻게든 따라가려고 설득하는 여주인공