제목 그대로이다.
나도 왜 만들었는지는 잘 모르겠지만 아무튼 만들어버려서, 앞으로 이걸 플레이하는 AI를 강화학습 또는 유전 알고리즘으로 학습시켜볼까 한다.
github.com/SyphonArch/brick_breaker
스크린샷
물리 구현
이게 또 보기와는 다르게 공 튕기는 것 구현이 생각보다 까다로워서 게임 매커닉을 제하고 공 튕기는 로직만 짜는데에 이틀이 걸렸다.
공과 벽돌이 겹치는 경우 반사 판정으로 처리하는 방식을 사용할 경우, 공의 경로가 부자연스러워질 듯 했고, 또 모서리에 튕기는 경우를 적절히 처리할 수 없을 것 같았다. 한 프레임에서의 공의 위치와 속도가 주어졌을 때, 그 다음 프레임에서의 공의 위치와 속도, 부딛힌 벽돌들을 정확히 계산하고 싶었다. 그래서 고등학교에서 배운 기하/벡터 지식을 이용해 수학적인 접근을 시도하였다.
충돌이 없다고 가정할 시, 현재 프레임과 다음 프레임의 공의 위치를 잇는 선분을 그려볼 수 있다. 이제 이 선분이 벽돌의 면 혹은 모서리와 교점이 있는지(정확히는 공의 반지름이 닿는지) 계산해주면 된다. 공의 반지름 처리를 위해 벽돌 주위로 공의 반지름과 동일한 경계선을 그려주고 이 선과 공의 중심 경로 선분이 겹치는지 보면 된다. 이러한 경계는 면 부분에서는 직선이, 모서리에서는 사분원이 된다.
그런데 모든 공마다 모든 벽돌과 이런 연산을 해주기에는 연산량도 많아지고, 다양한 경우에 대한 코딩을 해야 하기 때문에 짜기도 귀찮아진다. 그래서 고민을 조금 해보았더니, 프레임당 공의 이동거리가 충분히 작을 경우, 어떤 경우에도 공은 자신과 제일 가까운 칸 3개(상하/좌우에 각각 한칸씩, 또 대각선으로 한칸)와만 상호작용한다는 사실을 발견할 수 있었다. 그래서 일단 공이 위치한 칸을 찾아주고, 그 칸에 인접한 8개의 칸 중 어떤 3개의 칸을 확인하면 되는지 간단히 나눠준다면 전부 다 대칭성을 이용해 해결할 수 있게 된다. 설명을 하기 쉽지 않은데 아래의 그림을 보면 된다:
공이 현재 있는 칸에서, 공이 네개의 귀퉁이 중 어떤 귀퉁이에 가까운지를 기준으로 위의 그림처럼 (대칭이동을 통해) 살펴보아야 하는 세개의 칸이 왼쪽/위/대각선으로 오도록 만들어주면 된다는 뜻이다. 그럼 이제 우리의 관심사는 저 세개의 칸 중 어떤 칸에 벽돌이 존재하느냐... 라서 총 8가지의 경우가 존재한다. 왼쪽과 위쪽이 모두 존재할 경우, 대각선 위치에 벽돌이 존재하는지는 사실 중요하지 않고, 또 아무 벽돌도 존재하지 않는 경우도 trivial하므로 경우가 2가지 줄어 총 6가지로 줄어들긴 한다. 아무튼 이렇게 공의 현재 칸만 확인해서, 좌표의 원점을 위 그림에서 현재 칸의 왼쪽 위 귀퉁이로 설정한다면 6가지 경우에 대해 항상 같은 연산을 통해 충돌 여부와 교점 / 튕겨나가는 방향 등을 계산할 수 있다. 공이 어떻게 튕기는지를 확인하였다면, 다시 대칭을 시켜준 후에 현재 칸의 위치에 맞게 평행이동까지 해주면 된다(정확히 이렇게 짜지는 않았을 수도 있다; 기억이 잘 안난다. 아니 이틀 전에 짜놓고??).
6가지 각 경우에 대해 충돌이 발생했는지 확인하는 과정은 그냥 수학이므로 블로그에서는 생략하겠다. 어떻게 짰는지 관심있는 사람들은 위의 깃헙 레포에서 ball.py를 확인하면 된다.
결론
일단 원작처럼 잘 작동한다. (Time killing 성능 또한 원작만큼 좋다 ㅎ)
관련해서 AI를 만드는 것에 충분한 진전이 있다면 블로그에 업데이트를 올리도록 하겠다.
'개발 > 기타' 카테고리의 다른 글
드디어 스와이프 벽돌깨기 AI를 만들어 보았다 (0) | 2023.02.02 |
---|---|
Soldier-Link: 육군훈련소 인편 전달 웹사이트 구축하기 (0) | 2021.03.28 |