[42Seoul] so_long

werthers·2023년 10월 21일
0

42서울

목록 보기
7/7
post-thumbnail

2서클 나의 마지막 과제 so_long

mlx 라이브러리를 사용해서 플레이어가 Collect를 다 모으고 출구로 나가는 2D 게임을 구현하는 과제이다.
개인적으로 되게 재밌게 구현했다.

mlx란 42 자체에서 openGL을 사용해서 교육용으로 만든 그래픽 라이브러리이다.
서브젝트 내에 첨부되어 있는 mlx 라이브러리를 다운로드 받아서 컴파일 단계에서 -L./mlx -lmlx -framework OpenGL -framework AppKit와 같이 불러와 사용할 수 있다.

먼저 so_long은 textures와 maps를 허용하기 때문에 디렉토리를 먼저 생성하고, textures에는 png 파일을 본인이 사용할 픽셀 단위로 조절해서 xpm 파일로 만들어 저장해두고, maps에는 다양한 테스트를 해볼 .ber 확장자의 맵 파일을 저장해두면 된다.

42Docs mlx를 보면 mlx 내에 선언된 기능을 파악할 수 있다.

so_long에 사용할 함수 설명

먼저 mlx_init() 함수를 통해 mlx 객체를 void * 형태로 선언해준다.

새로운 윈도우를 사용하기 위해 win 객체를 void *로 받는 mlx_new_window() 함수를 통해 설정해준다.
자세한 프로토타입은 위 문서에 잘 나와있다.

게임을 하기 위해선 key event 발생 시 호출할 함수를 mlx_hook 함수를 통해 걸어준다.

이 때, 각 key event에 대한 상수가 따로 설정이 되어 있기 때문에 예를 들어 KEY_RELEASE=3과 같이 사용할 이벤트에 대해 훅을 걸어주면 된다.

textures 디렉토리에 넣어둔 사용할 이미지 파일 (.xpm)을 mlx image로 사용하기 위해 mlx_xpm_file_to_image로 변수에 할당한다.

이미지 변수를 mlx_put_image_to_window 함수를 통해 윈도우에 이미지를 렌더링한다.

구현

so_long을 구현하며 가장 까다로운 부분이 map parsing 부분이다.
여러가지 유효성 검사를 해야하는데 기억나는 순서대로 작성해본다.

  1. map name 유효성 : .ber 확장자를 사용하는 파일만 가능하다.
  2. map 유효성 : 맵은 10EPC만을 포함할 수 있으며 그 외의 글자는 허용되지 않는다. 맵은 1(벽)으로 감싸져있어야 하며 직사각형이어야 한다. 또, C(수집품)를 다 먹을 수 있으며, E(출구)에 도달할 수 있어야 한다.

여기가 참 힘든데 맵이 비었을 때, 맵이 개행으로 끝났을 때, E(출구)가 2개 이상, P(플레이어 시작 위치)가 2개 이상일 때 모두 invalid로 처리해야한다.

우선, GNL을 통해 한 줄씩 map을 읽어온다.

나는 1차원 배열을 통해 문제를 해결했기 때문에 첫 줄을 width의 기준으로 잡고 개행을 제거하며 width를 비교하며 heigth를 증가시키며 ft_strjoin을 통해 문자열을 붙인다.

이후 ft_strlen을 통해 마지막 글자가 \n인지 확인하고 있다면 invalid 처리한다.

맵이 문자열로 완성되었다면 모든 글자에 10EPC를 제외한 글자가 있는지 확인한 후 첫 줄과 마지막 줄, 제외한 각 라인의 처음과 마지막 인덱스가 벽인지 확인한다.

E와 P와 C의 갯수를 각각 체크해서 C가 1이상이고 E, P가 유일하게 존재하는지 확인한다.

마지막으로 DFS 혹은 BFS를 통해 C를 다 먹을 수 있는 map인지, E에 도달할 수 있는 map인지 확인해야한다.

나는 DFS를 통한 재귀함수로 맵의 유효성을 확인했지만, 원형 큐를 이용한 BFS가 구현면에서 (특히 42에서) 어렵지만 성능면에서 맵의 유효성을 확인하기 적합한 알고리즘이기 때문에 선택에 따라 갈릴 것 같다.

맵이 유효하다면 이제 mlx_put_image_to_window 함수를 통해 초기 맵을 렌더링하고, mlx_loop 함수를 통해 이벤트를 대기한다.

이제 mlx_hook을 통해 걸어놨던 KEY_RELEASE 이벤트가 발생했다면 key_event를 통해 WASD키인지 체크해서 각각의 키가 눌렸을 때 갈 방향에 P를 옮기고 다시 그림을 렌더링한다.

profile
Hello World !

0개의 댓글