Home So_long ③ 구현 과정
Post
Cancel

So_long ③ 구현 과정

game_play.gif

방법 구상

과제 구현

  • 맵 파싱
  • 이미지 띄우기
  • 맵 따라 이미지 그리기
  • 플레이어 움직이기
  • 이미지 소스 찾기
  • 에러 처리

보너스 구현

  • 이동 동작 스프라이트 구현
  • 화면에 걸음 수 표시
  • 터미널 걸음 수 출력 지우기
  • 순찰하는 적 구현

mlx 함수 연습

  • 라이브러리를 이용해 창 띄우기 (mlx_init, mlx_new_window) empty_window.png
  • 키보드 이벤트 받기 (mlx_hook, mlx_loop)
  • 이미지 포인터 생성하기 (mlx_xpm_file_to_image)
  • 이미지 화면에 띄우기 (mlx_put_image_to_window) one_box.png

맵 파싱

인자 체크

  • 인자가 2개인지
  • 파일명이 *.ber 형태인지
1
2
dot = ft_strrchr(filename, '.');
ft_memcmp(dot, ".ber", 5)

위와 같이 뒤에서부터 . 을 찾아서 해당 위치부터 .ber 문자열과 비교해서 유효한 파일명인지를 체크하였다.

맵 저장

  • 인자의 파일을 get_next_line으로 읽는다.
  • 개행문자가 포함된 하나의 문자열로 이어준다.
  • ft_split을 사용해 이차원 배열로 저장한다.

유효한 맵인지 체크

인자에 나와있는 파일을 read해서 맵에 저장

저장된 맵을 돌며 유효한 맵인지 체크

직사각형인지 확인

1
2
if ((int)ft_strlen(line) - !!ft_strchr(line, '\n') != game->map.col)
	print_error("Map isn't rectangular.", NULL);

해당 line에서 널문자를 제외한 길이가 column의 개수와 다른지를 확인하였다.

ft_strchr은 NULL 또는 문자가 위치한 주소값을 반환하기 때문에 !을 두번 처리해 0또는 1로 만들었다.

벽으로 둘러쌓였는지 확인

map 배열의 가장자리를 돌면서 요소가 1인지를 확인하였다.

요소가 충분한지 확인

배열을 돌면서 C, E, P가 조건을 만족하는지를 확인했다.

이미지 구현

다양한 이미지 표시

바닥과 벽은 각각 두 개의 이미지를 만들어서 아래와 같이 위치에 따라 이미지를 번갈아가며 표시했다.

1
2
3
4
5
6
7
void	draw_ground(t_game *game, int x, int y)
{
	if ((x / PX + y / PX) % 2 == 1)
		mlx_put_image_to_window(game->mlx, game->win, game->ground1.ptr, x, y);
	else
		mlx_put_image_to_window(game->mlx, game->win, game->ground2.ptr, x, y);
}

결과물

1
2
3
4
11111
100P1
1C0E1
11111

play

1
2
3
4
5
11111111111111
10010000000C01
10000111110001
1P0011E0000001
11111111111111

play

1
2
3
4
5
6
1111111111111111111
110000000100C0010E1
100000C100000100001
1010010101C10001001
1P000001C00001001C1
1111111111111111111

play

Bonus part

걸음수 출력

print_moves.gif

mlx_string_put 함수를 사용해 원하는 위치에 색상을 지정해 화면에 출력했다.

스프라이트 구현

sprite.gif

4*4 크기의 이차원 배열에 각 방향별로 움직인 정도에 따른 이미지를 저장했다.

입력 방향과 총 걸음수를 저장해 두었다.

이미지를 player[dir][move%4].ptr 형태로 불러왔다.

예외 사항 처리

  • 맵이 직사각형이 아닌 경우
  • 맵이 벽으로 둘러쌓이지 않은 경우
  • 맵의 요소가 불충분한 경우
  • mlx 생성 실패한 경우
  • 윈도우 생성 실패한 경우
  • 이미지가 포인터에 저장되지 않은 경우

에러 처리

메모리 누수

leaks 개인 맥으로 테스트를 돌렸을 때 위와 같이 메모리 누수가 발생하였다. 디버깅 결과, init 과정에서 mlx_init()함수를 사용할 때 해당 문제가 발생하는 것을 확인했다. opengl이 아닌 mms를 사용하면 해당 문제가 해결된다는 이야기를 들었지만 컴파일 과정에서 문제가 계속 발생해 변경하지 않기로 했다. leaks 클러스터에서 다시 테스트를 돌려보니 이번에는 누수가 발생하지 않았다.

캐릭터가 멈춰있는 문제

방향키를 반복해서 눌러도 캐릭터가 시작지점에 멈춰있는 에러가 발생했다. 그러다가 임의의 횟수가 되면 segmentation fault 가 발생했다. stuck 근본적인 발생 원인은 찾지 못했지만 game 구조체에 선언하는 멤버의 개수가 일정 개수를 넘어갈 때마다 반복해서 발생하는 것으로 확인했다.. 따라서 해당 개수 이하로 줄여서 문제를 해결했다.

총평

부족한 부분

파일명 체크 과정

기존에는 유효한 파일명인지를 ft_strchr(filename, '.') 로 앞에서부터 .의 여부를 체크했는데 이렇게 한다면 ./so_long ./map/map1.ber 과 같이 파일명이 주어진 경우 맨 뒤의 .ber 대신 ./map 을 확인해서 invalid filename으로 처리하게되는 문제가 발생한다.

유효한 파일명은 항상 맨 마지막이 .ber형태이기 때문에 ft_strchr 대신 ft_strrchr을 사용한다면 해당 문제가 발생하지 않게된다.

perror, strerror의 미사용

과제를 진행하면서 위 두 함수의 적절한 사용처를 찾지 못해 사용하지 않았다.

개선 방향

  • perror의 사용
    errno 개념을 공부해서 다양한 상황에서 에러메시지를 구현할 수 있게 하기.

  • 순찰하는 적 구현
    맵 상의 '0' 요소 중 하나를 정해서 특정 문자로 바꾼 후 일정 시간마다 좌표를 수정해주면 될 것 같다.

  • 게임 시작과 성공할 때의 효과 / 이미지 구현

This post is licensed under CC BY 4.0 by the author.

So_long ② 배경 지식

Philosophers ① Subject