- 시저암호
이 문제는 각 알파벳을 일정한 거리만큼 밀어서 다른알파벳으로 바꾸는 암호화방식을 만드는것이다.
using System;
public class Solution {
public string solution(string s, int n) {
string answer = "";
foreach(char c in s)
{
if(c!=' ')
{
int tmp = 0;
//아스키 코드 A=65, Z=90, a=97, z=122
if((int)c<91)
{
tmp = (int)c + n;
if(tmp>90) tmp = 64 + (tmp-90);
}
else
{
tmp = (int)c + n;
if(tmp>122) tmp = 96 + (tmp-122);
}
answer += Convert.ToChar(tmp);
}else
answer += ' ';
}
return answer;
}
}
알파벳의 아스키코드를 이용하여 문제를 풀면 쉽게 해결가능할거라 판단하여 코드를 작성하였다.
숫자를 대, 소문자로 정확히 구분하는법은 검색을통해 코드에 입력하였다.
- 배열과 List, ArrayList, Dictionary 의 차이점을 설명해주세요.
- (꼬리질문) Dictionary는 어떻게 구현해야 하나요?
- (꼬리질문) Dictionary 검색이 빠른 이유는 무엇인가요?
배열은 생성시 크기할당이 필요하고 인덱스를 통해 접근이 가능합니다.
리스트는 크기할당이 필요없고 인덱스없이 접근이 가능합니다. 또한 앞의 요소가 삭제되면 새로추가되는 요소가 그 공간에 저장가능합니다.
ArrayList는 인덱스로 식별자를 쓰는것이 가능하고 크기를 동적으로 사용할수 있습니다.
Dictionary는 해시테이블을 기반으로 Key-Value Pair형태로 데이터를 저장합니다.
Dictionary의 구현은 키와 값의 쌍으로 이루어진 자료구조 해시함수를 이용해야하며 검색이 빠른 이유는 어떠한 임의의 값에 대하여 고정된 크기의 고유한 값으로 매핑된 해시값을 이용해 찾기때문입니다.
주말동안 캐릭터 점프버퍼와 일정값이내로 머리가 천장에 부딪히면 부드럽게 밀려나면서 점프가 지속되도록하는 코드를 제작하였다.
먼저 점프버퍼이다.
[SerializeField] private float _jumpBufferTime = 0.2f;
private float _jumpBufferCount;
//점프타임
private float _jumpingTime;
//플레이어 점프 체크
private bool _isJumping;
점프버튼을 누르고 0.2초 이내로 땅에 닿는다면 점프버튼이 입력된값을 기억하고있다 점프를 할수 있게 하는것이 점프버퍼이다.
먼저 0.2의 값을 가지고있는 _jumpBufferTime과 점프버튼을 누른순간 값이들어가 Time.deltaTime으로 값이 떨어지는 _jumpBufferCount를 선언해주었다.
그리고 점프시간의 최대시간을 체크해주기위해 _jumpingTime을 선언해주어 너무 오래 점프를 할수없게 만들었다.
마지막으로 플레이어의 점프상태를 체크하는 _isJumping을 선언해주면 준비는 끝난다.
//점프를 눌렀을 때
if (_isJumping)
{
_jumpBufferCount = _jumpBufferTime;
}
else
{
_jumpBufferCount -= Time.deltaTime;
}
//점프
if (_coyoteTimeCount > 0f && _jumpBufferCount > 0f && _jumpingTime > 0f)
{
_rigidbd.velocity = new Vector2(_rigidbd.velocity.x, _jumpingPower);
_jumpBufferCount = 0f;
}
public void JumpStarted(InputAction.CallbackContext context)
{
_jumpingTime = 0.05f;
_isJumping = true;
}
public void JumpCanceled(InputAction.CallbackContext context)
{
if (_rigidbd.velocity.y >= 0f)
{
_rigidbd.velocity = new Vector2(_rigidbd.velocity.x, _rigidbd.velocity.y * 0.6f);
_coyoteTimeCount = 0f;
}
_isJumping = false;
}
점프버튼을 누르면 _isJumping이 true로 바뀌며 _jumpingTime에 0.05f값이 들어간다. 점프코드에선 3가지 조건이 전부 충족되면 점프가 실행된다. 만약 플레이어가 땅에닿기 0.2초전에 점프버튼을 누르게되면 코요테타임을제외한 2값이 0보다커지게되고 땅에닿는순간 코요테타임도 0.2값을 가지게되어 3가지조건이 전부충족되기때문에 Update문이 돌아가 점프를 하게된다.
다음으로 머리충돌체크이다.
//오른쪽 머리 충돌체크
private bool IsRightHead()
{
//레이 발사 / 정상 작동
for (int i = -4; i < 5; i++)
{
if(Physics2D.Raycast(transform.position + (Vector3.right * 0.125f * i), Vector2.up, 1.5f, _floorLayer))
{
if(i == 4)
{
transform.position = new Vector3(transform.position.x - 0.127f, transform.position.y);
}
return true;
}
}
return false;
}
//왼쪽 머리 충돌체크
private bool IsLeftHead()
{
for (int j = -4; j < 5; j++)
{
if (Physics2D.Raycast(transform.position + (Vector3.right * -0.125f * j), Vector2.up, 1.5f, _floorLayer))
{
if (j == 4)
{
transform.position = new Vector3(transform.position.x + 0.127f, transform.position.y);
}
return true;
}
}
return false;
}
캐릭터의 중앙기준 0.125씩 레이를쏴서 총9개의 레이를 쏜다. 만약 좌,우 맨 마지막 레이만 _floorLayer에 닿게되면 플레이어의 위치가 0.127f만큼 밀려나면서 점프력은 유지되어 머리가 레이어에 부딪치지않고 점프를 유지하게된다.
이 코드에서 버그가 있었는데 레이캐스트가 _floorLayer에 부딪혀 플레이어가 이동하기전에 점프속도가빨라 이동하기전 머리가 부딪힌판정이 나는것이었다. 이것은 레이의 길이를 1.1에서 1.5로 늘리는방식으로 해결하였다.
그리고 레이를 2개쏘는것은 한개를 쏘게되면 4 또는 -4에서 제일먼저 부딪힌 판정이나 플레이어가 무조건 밀리는 현상이 발생하여 좌 우 두개의 레이어에 다른조건을 주는방식으로 해결하였다.
이것으로 플레이어의 이동, 점프, 점프버퍼, 코요테타임, 일정값이내로 머리를 부딪혔을때 부드럽게 점프가 계속되도록하는 기능을 구현완료하였다. 오늘부터는 에어 캐릭터로직작업에 들어갔다.
먼저 캐릭터의 무기가 마우스의 위치를 바라보면서 회전하도록 제작아였다.
//에어 무기 회전
[SerializeField] private SpriteRenderer _armRenderer;
//총구위치
[SerializeField] private Transform _armPivot;
[SerializeField] private SpriteRenderer _characterRenderer;
[SerializeField] private SpriteRenderer _weaponSprite;
//마우스가 움직인 값
private Vector2 _mouseDelta;
private Camera _camera;
private void Awake()
{
_camera = Camera.main;
}
private void FixedUpdate()
{
RotateArm();
}
public void Look(InputAction.CallbackContext context)
{
_mouseDelta = context.ReadValue<Vector2>();
}
//에어 무기회전 및 방향전환
private void RotateArm()
{
Vector2 worldPos = _camera.ScreenToWorldPoint(_mouseDelta);
Vector2 newAim = worldPos - (Vector2)_armPivot.position;
float rotZ = Mathf.Atan2(newAim.y, newAim.x) * Mathf.Rad2Deg;
_armRenderer.flipY = Mathf.Abs(rotZ) > 90f;
_characterRenderer.flipX = _armRenderer.flipY;
_weaponSprite.flipX = _armRenderer.flipY;
_armPivot.rotation = Quaternion.AngleAxis(rotZ, Vector3.forward);
}
스파르타코딩클럽 입문강의에서 사용했던 탑다운코드를 인용하여 코드를 제작하였다. 입문강의에서 사용했던코드와 우리팀이 제작하는 코드에서 사용하는 코드가 달라 적용하는데 상당히 애를 먹었었다. 모르는 부분은 같은조원에게 물어보고 같이 고민하면서 해결해 현재 정상적으로 작동을하는모습을 보니 마음에 든다.
이제 에어의 캐릭터로직에 대해 고민을 해야한다.
먼저 클릭을 지속하는동안 overlapCircleAll메서드를 통해 총구를 기준으로 일정범위내 원형범위내에 존재하는 모든 오브젝트의 위치를 알아내고 마우스위치를 기준으로 일정각도이내에 존재하는 오브젝트중 제일 가까운 오브젝트를 끌어당기는 코드를 작성하면된다. 빨아들인 오브젝트는 라인렌더러를 사용해 날아가는모션이 보이도록 제작을해야한다.
일단 제일먼저 overlapCircleAll을 했을때 거리체크를 한다음 가까운거리에 저장, 계속검사를하면서 제일 가까운 오브젝트를 찾아내 가져온다.
말로 적으니 좀 정신없는거같다..
일단 마우스클릭을 하고있는동안 Debug.Log가 작동하도록 코드를 제작한상태이다. 내일은 가장가까운 오브젝트가 총구위치로 이동하는코드를 제작할예정이다.