so_long과제는 map에서 수집품을모아 포탈로 탈출하면되는 게임을 만드는 것이다
map은 5가지 요소로 구성되어져 있다
지도가 .ber파일이 맞는지 검사한다
int check_map_name(char *arr)
{
unsigned long long len;
len = ft_strlen(arr); //map 파일이름길이를 구한다
if (len <= 4) // map파일이 4글자 이하라면 오류이므로 1을 반환한다
return (1);
if (arr[len - 1] == 'r' && arr[len - 2] == 'e' && \
arr[len - 3] == 'b' && arr[len - 4] == '.')
// 맵이름의 맨 뒤에서부터 한글자씩 비교해 .ber파일이 맞는지 검사한다
return (0); // 맞으면 정상맵으로 0을 반환한다
return (1); // 아니면 맵 오류로 1을 반환한다
}
지도에 포탈과 플레이어 수집품이 정상 갯수만큼 존재하는지 확인하는 부분이다
int check_map_item(char *map, t_map_check *map_check, int i)
{
while (map[i]) // map을 전체 탐색한다
{
if (map[i] == 'C') // 수집품(C)가 발견되었으면 map_check->c의 값을 1증가시킨다
map_check->c += 1;
else if (map[i] == 'P') // 플레이어(P)가 발견되었으면 map_check->p의 값을 증가시킨다
{
map_check->player = i;
map_check->p += 1;
}
else if (map[i] == 'E')// 포탈(E)가 발견되었으면 map_check->p의 값을 증가시킨다
map_check->e += 1;
else if (map[i] == '0' || map[i] == '1')
;
else if (map[i] == '\n')
map_check->y += 1;
else
return (1);
i++;
}
if (map_check->p != 1 || map_check->e != 1 || map_check->c <= 0)
//플레이어, 포탈, 수집품을 갯수에 이상이 있을 시 1을 반환하여 오류를 표시한다
return (1);
return (0);
}
지도가 벽으로 둘러싸여 있는지 확인한다
int check_map_closed(char *map, t_map_check *map_check, int i)
{
while (map[i]) //map을 전체 탐색한다
{
if (i < map_check->x && map[i] != '1')
// i가 map_check->x 보다 작다는 말은 map의 맨 윗줄을 의미한다
return (1);
else if (i % (map_check->x + 1) == 0 && map[i] != '1')
// i % map_check->x + 1 == 0이라는 말은 맵의 맨 왼쪽줄을 의미한다
// +1을 해준이유는 map안에 개행이 포함되어져 있어서 1을 더해준다
return (1);
else if ((i % (map_check->x + 1)) == map_check->x - 1 && map[i] != '1')
// i % map_check->x + 1 == map_check->x - 1 이라는 말은 맵의 맨 오른쪽줄을 의미한다
// -1을 해준이유는 map안에 개행이 포함되어져 있어서 1을 빼준다
return (1);
else if (i >= (map_check->x + 1) * (map_check->y - 1) && \
i < ((map_check->x + 1) * map_check->y) - 1)
// x에 y - 1을 곱해준 위치와 x에 y를 곱한위치에 1을 뺀 사이를 검사하여 맵의 맨 아랫줄을 검사한다
{
if (map[i] != '1')
return (1);
}
i++;
}
return (0); // 이상이 없으면 0이 반환된다
}
맵에 유효한 경로가 있는지 확인하는 코드이다 dfs를 사용하여 유효한지 검사한다
👀 dfs(깊이우선탐색) : dfs란 전체 탐색을 하는 알고리즘 중 하나로 하나의 경로로 쭉 파고들어 끝까지 확인한 후 다시 이전으로 돌아와서 다음경로를 끝까지 파고든다 이러한 동작은 모든 장소를 확인할때 까지 반복해서 동작한다
void dfs(char *map, t_map_check *map_check, int player)
{
int move[4];
int i;
move[0] = player - map_check->x - 1; // 현재 플레이어를 위로 한칸 움직인다
move[1] = player + 1; // 현재 플레이어를 오른쪽으로 한칸 움직인다
move[2] = player - 1; // 현재 플레이어를 왼쪽으로 한칸 움직인다
move[3] = player + map_check->x + 1; // 현재 플레이어를 아랫쪽으로 한칸 움직인다
i = 0;
map_check->dfs_map[player] = 1; // 플레이어가 방문했으면 dfs_map에 해당위치를 1로 갱신해준다
if (map[player] == 'C') // 현재위치에 수집품이 있다면 dfs_c 갯수를 하나 늘려준다
map_check->dfs_c += 1;
while (i != 4) // 배열을 0~3까지넣으면서 플레이어를 현재위치에서 상하좌우로 이동시켜보며 검사를 진행한다
{
if (map[move[i]] != '1' && map_check->dfs_map[move[i]] != 1)
// 플레이어를 움직인 위치가 1(벽)이 아니고 dfs_map != 1 방문한적이 없으면 이동시킨다
{
if (map[move[i]] == 'E') // 이동한위치에 포탈이 있다면 dfs_e 갯수를 하나 늘린다
map_check->dfs_e += 1;
else
dfs(map, map_check, move[i]);
// 현재 플레이어 위치를 갱신하여 재귀함수를 호출한다
}
i++;
}
}
이렇게 dfs에서 얻은 값 들로 뒷부분 코드에서 맵에서 전체 탐색한 수집품 갯수와 dfs를 진행하면서 얻은 수집품 갯수를 비교 포탈에 방문했는지도 확인하여 맵에 유효한 경로가 존재하는지 검사한다
if (map_check.dfs_c == map_check.c && map_check.dfs_e >= 1)
{
free(map_check.dfs_map);
return (0);
}
game이 실행되는 동안 모든 입력은 so_long함수에서 처리가 되어진다
int so_long(char *game_map)
{
t_param maps;
maps.map = game_map;
map_cnt(&maps); // map의 수집품 갯수를 카운트 해준다, 디스플레이 크기보다 맵의 크기가 큰지 테스트한다
enemy_add(&maps, 0, 0, 500); // BONUS과제 적을 랜덤하게 추가해준다
maps.mlx = mlx_init(); // 디스플레이 장치와 연결하여 maps.mlx에 연결해준다
image_init(&maps); // 게임에 쓸 image파일들을 연결해준다
maps.user.x = 0;
maps.user.direction = 1;
maps.check_attack = 0;
maps.waitting_attack = 0;
mlx_key_hook(maps.win, &key_press, &maps); // key입력을 받아 동작할 hook함수이다
mlx_loop_hook(maps.mlx, &draw, &maps); // loop를 진행할때마다 동작할 hook함수이다
mlx_hook(maps.win, 17, 0, &red_botton_delete, &maps); // red_botton(종료버튼)을 눌렀을때 동작할 hook함수이다
mlx_loop(maps.mlx); // loop함수를 호출하여 게임이 꺼지지않는 상태로 event를 받게 만들어준다
return (0);
}
맵의 크기가 디스플레이 크기보다 큰지 테스트하고 맵의 수집품 갯수를 세팅해준다
void map_cnt(t_param *maps)
{
int i;
int max_win_width;
int max_win_height;
maps->win_height = 0;
maps->win_width = 0;
maps->collection = 0;
i = 0;
while (maps->map[i])
{
if (maps->map[i] == '\n')
maps->win_height += 1; // 개행을 발견할때 마다 height를 증가시킨다
else if (maps->map[i] == 'C')
maps->collection += 1; // 수집품을 발견할때 마다 수집품 갯수를 늘려준다
i++;
}
maps->win_width = (i - maps->win_height)
// maps->win_height; // height를 이용하여 맵의 width를 계산해준다
mlx_get_screen_size(maps->mlx, &max_win_width, &max_win_height);
// 현재 디스플레이 장치의 scrren size를 구해주는 함수이다
if (max_win_width < maps->win_width * 64 || \
max_win_height < (maps->win_height + 1) * 64)
// 64x64픽셀 크기의 이미지를 사용하기 때문에 width 와 height에 64를 곱해서
// 그 크기를 이용해 맵의 크기가 디스플레이 크기보다 큰지 검사해준다
error(4);
maps->move_cnt = 0;
}
맵에는 적의 위치정보가 포함되어져 있지 않기 때문에 랜덤한 위치에 적을 생성시켜주는 함수이다
void enemy_add(t_param *maps, int enemy, int enemy_position, int cnt)
{
if (maps->win_width * maps->win_height < 90)
// 맵의 크기에 맞게 임의로 적의 숫자를 세팅해준다
enemy = 1;
else if (maps->win_width * maps->win_height < 150)
enemy = 2;
else if (maps->win_width * maps->win_height < 210)
enemy = 3;
else if (maps->win_width * maps->win_height < 270)
enemy = 4;
else
enemy = 5;
srand(time(NULL)); // srand함수에 현재시간을 넣어줘서 rand함수의 seed값을 세팅해준다
while (enemy != 0 && cnt != 0)
{
enemy_position = rand() % ((maps->win_width + 1) * maps->win_height);
// rand함수를 이용하여 랜덤으로 적의 위치를 정해 만들어준다
if ((maps->map)[enemy_position] == '0')
{
(maps->map)[enemy_position] = 'L';
enemy--;
}
cnt--;
}
}
프로그램 밖에 있는 image file들을 프로그램안에 있는 구조체에 연결해주는 함수이다
void image_init(t_param *maps)
{
maps->win = mlx_new_window(maps->mlx, maps->win_width * 64, \
(maps->win_height + 1) * 64, "minkyole's so_long");
// window size를 map_cnt에서 계산한 width height값을 이용하여 만들어준다
maps->user.image = mlx_xpm_file_to_image(maps->mlx, \
"texture/p.xpm", &maps->user.wi, &maps->user.he);
// 각각의 구조체에 image를 매칭시켜준다
maps->wall.image = mlx_xpm_file_to_image(maps->mlx, \
"texture/1.xpm", &maps->wall.wi, &maps->wall.he);
maps->land.image = mlx_xpm_file_to_image(maps->mlx, \
"texture/0.xpm", &maps->land.wi, &maps->land.he);
maps->chase.image = mlx_xpm_file_to_image(maps->mlx, \
"texture/c.xpm", &maps->chase.wi, &maps->chase.he);
maps->potal[0].image = mlx_xpm_file_to_image(maps->mlx, \
"texture/close_potal.xpm", &maps->potal[0].wi, &maps->potal[0].he);
maps->potal[1].image = mlx_xpm_file_to_image(maps->mlx, \
"texture/open_potal.xpm", &maps->potal[1].wi, &maps->potal[1].he);
user_sprite_init(maps);
// sprite들은 여러장의 image가 순차적으로 나와 움직이는것처럼 보여지므로
// 연결시켜줄 image가 많아 함수를 따로 빼서 초기화해주었다
enemy_sprite_init(maps);
attack_sprite_init1(maps);
attack_sprite_init2(maps);
attack_sprite_init3(maps);
keybord_init(maps);
}
loop_hook함수의 콜백함수로서 loop가 이루어질때마다 화면에 image를 그려준다
int draw(t_param *maps)
{
unsigned long long i;
static long long cnt; // 동적인 image를 그려줄때 사용할 static변수이다
i = 0;
while (maps->map[i]) // 맵을 전체탐색하면서 순서대로 그려준다
{
draw_map(maps, i, cnt); // 맵을 그려준다
i++;
}
draw_attack(maps, i, ((maps->win_width + 1) * \
(maps->win_height + 1)) - 2, maps->move_cnt);
// 공격모션을 그려준다
cnt++; // 동적인 image를 그려줄때 사용할 cnt를 증가시켜준다
return (0);
}
현재 위치의 맵이 무었인지 확인하여 그에 맞는 이미지를 그려준다
void draw_map(t_param *maps, unsigned long long i, int cnt)
{
draw_image(1, maps, i);
if (maps->map[i] == '1')
draw_image(2, maps, i);
else if (maps->map[i] == 'P' && \
(maps->user.direction == 1 || maps->user.direction == 3))
//user.direction에 맞춰 플레이어의 방향을 설정해서 그려줍니다
draw_user_r(cnt, maps, i);
else if (maps->map[i] == 'P' && \
(maps->user.direction == 2 || maps->user.direction == 4))
draw_user_l(cnt, maps, i);
else if (maps->map[i] == 'C')
draw_image(4, maps, i);
else if (maps->map[i] == 'E' && maps->collection == 0)
draw_image(6, maps, i);
else if (maps->map[i] == 'E')
draw_image(5, maps, i);
else if (maps->map[i] == 'R')
draw_enemy_r(cnt, maps, i);
else if (maps->map[i] == 'L')
draw_enemy_l(cnt, maps, i);
}
flag에 맞춰서 해당하는 image를 mlx_put_image_to_window함수를 이용하여 그려준다 (정적인 image)
void draw_image(int flag, t_param *maps, unsigned long long i)
{
if (flag == 1)
mlx_put_image_to_window(maps->mlx, maps->win, \
(maps->land).image, i % (maps->win_width + 1) * 64, \
i / (maps->win_width + 1) * 64);
// 해당하는 image와 좌표를 계산하여 그려줍니다
else if (flag == 2)
mlx_put_image_to_window(maps->mlx, maps->win, \
(maps->wall).image, i % (maps->win_width + 1) * 64, \
i / (maps->win_width + 1) * 64);
else if (flag == 3)
mlx_put_image_to_window(maps->mlx, maps->win, \
(maps->user).image, i % (maps->win_width + 1) * 64, \
i / (maps->win_width + 1) * 64);
else if (flag == 4)
mlx_put_image_to_window(maps->mlx, maps->win, \
(maps->chase).image, i % (maps->win_width + 1) * 64, \
i / (maps->win_width + 1) * 64);
else if (flag == 5)
mlx_put_image_to_window(maps->mlx, maps->win, \
(maps->potal[0]).image, i % (maps->win_width + 1) * 64, \
i / (maps->win_width + 1) * 64);
else if (flag == 6)
mlx_put_image_to_window(maps->mlx, maps->win, \
(maps->potal[1]).image, i % (maps->win_width + 1) * 64, \
i / (maps->win_width + 1) * 64);
}
동적인 image를 그릴때 사용하는 함수중 하나이다 loop를 할때마다 증가하는 static변수인 cnt를 사용하여 image를 번갈아가며 그려 애니메이션 느낌을 준다
void draw_user_r(int cnt, t_param *maps, unsigned long long i)
{
if (cnt % 80 <= 20 // cnt에 맞춰서 image들을 순서대로 그려준다
mlx_put_image_to_window(maps->mlx, maps->win, \
(maps->user_sprite[0]).image, i % (maps->win_width + 1) * 64, \
i / (maps->win_width + 1) * 64);
else if (cnt % 80 <= 40)
mlx_put_image_to_window(maps->mlx, maps->win, \
(maps->user_sprite[1]).image, i % (maps->win_width + 1) * 64, \
i / (maps->win_width + 1) * 64);
else if (cnt % 80 <= 60)
mlx_put_image_to_window(maps->mlx, maps->win, \
(maps->user_sprite[2]).image, i % (maps->win_width + 1) * 64, \
i / (maps->win_width + 1) * 64);
else
mlx_put_image_to_window(maps->mlx, maps->win, \
(maps->user_sprite[3]).image, i % (maps->win_width + 1) * 64, \
i / (maps->win_width + 1) * 64);
maps->user.x = i;
}
score를 그려주고 공격 버튼을 눌러졌는지 확인하여 공격모션을 그려준다
void draw_attack(t_param *maps, int i, int score_end, int move_cnt)
{
static int attack_cnt;
// cnt를 사용하면 공격이 처음부터 그려지지않고 3번 image부터 그려지는 등 오류가 발생하여 attack에서 사용할 attack_cnt를 선언해준다
while (i <= score_end)
// 플레이어가 이동할때마다 늘어날 score를 그려준다
{
draw_image(1, maps, score_end);
draw_score1(move_cnt % 10, maps, score_end);
// move_cnt % 10이 0 ~ 4일 경우 그려준다
draw_score2(move_cnt % 10, maps, score_end);
// move_cnt % 10이 5 ~ 9일 경우 그려준다
move_cnt = move_cnt / 10
score_end--;
}
if (maps->check_attack == 1)
// check_attack이란 공격방향을 결정해주는 플래그로check_attack에 맞춰 함수를 호출한다
draw_right_attack(attack_cnt, maps, \
maps->user.x + 1, (maps->win_width + 1));
else if (maps->check_attack == 2)
draw_left_attack(attack_cnt, maps, \
maps->user.x - 2, (maps->win_width + 1));
else if (maps->check_attack == 3)
draw_up_attack(attack_cnt, maps, \
maps->user.x - maps->win_width - 1, (maps->win_width + 1));
else if (maps->check_attack == 4)
draw_down_attack(attack_cnt, maps, \
maps->user.x, (maps->win_width + 1));
else
attack_cnt = 0; // 공격동작이 끝나면 attack_cnt를 초기화해준다
attack_cnt++; // attack_cnt를 계속 증가시켜준다
}
공격모션을 그리는 방법이다
void draw_right_attack(int cnt, t_param *maps, int i, int width)
{
if (cnt % 30 <= 5)
// attack_cnt를 이용하여 순차적으로 공격모션을 출력한다
mlx_put_image_to_window(maps->mlx, maps->win, \
(maps->attack_sprite[0]).image, i % width * 64, i / width * 64);
else if (cnt % 30 <= 10)
mlx_put_image_to_window(maps->mlx, maps->win, \
(maps->attack_sprite[1]).image, i % width * 64, i / width * 64);
else if (cnt % 30 <= 15)
mlx_put_image_to_window(maps->mlx, maps->win, \
(maps->attack_sprite[2]).image, i % width * 64, i / width * 64);
else if (cnt % 30 <= 20)
mlx_put_image_to_window(maps->mlx, maps->win, \
(maps->attack_sprite[3]).image, i % width * 64, i / width * 64);
else if (cnt % 30 <= 25)
mlx_put_image_to_window(maps->mlx, maps->win, \
(maps->attack_sprite[4]).image, i % width * 64, i / width * 64);
else if (cnt % 30 <= 30)
mlx_put_image_to_window(maps->mlx, maps->win, \
(maps->attack_sprite[5]).image, i % width * 64, i / width * 64);
if (cnt % 30 == 29)
maps->check_attack = 0;
// 공격모션이 모두 출력되었으면 check_attack을 0으로 초기화하여 공격을 마무리한다
}
키보드 입력이 들어오면 mlx_key_hook 함수에서 콜백함수로 호출되어 동작한다
int key_press(int keycode, t_param *maps)
{
if (keycode == KEY_ESC) // ESC가 입력되었으면 프로그램을 종료시킨다
exit(0);
if (keycode == KEY_ATTACK) // 공격키가 눌러졌으면 waitting_attack 플래그를 1로바꾼다
{
maps->waitting_attack = 1;
return (0);
}
if (key_attack_up_down(keycode, maps) || \
key_attack_left_right(keycode, maps, maps->user.x))
return (0); // 공격모션중이면 종료시킨다
if (maps->move_cnt % 30 == 29) // 플레이어가 30걸음을 이동할 때마다 적을 추가로 생성한다
enemy_add(maps, 0, 0, 500); // 랜덤범위에 적을 생성한다
if (keycode == KEY_RIGHT) // 방향키가 입력되었으면 그에 맞춰서 direction을 설정한다
maps->user.direction = 1;
else if (keycode == KEY_LEFT)
maps->user.direction = 2;
else if (keycode == KEY_UP)
maps->user.direction = 3;
else if (keycode == KEY_DOWN)
maps->user.direction = 4;
else // 그외 입력이 들어오면 함수를 탈출한다
return (0);
move_map(keycode, maps); // 입력된 방향에맞게 유저를 이동시킨다
return (0);
}
공격버튼이 눌러지고 난 이후에 방향키 입력이 들어오면 해당방향에 공격을 진행하게 한다
int key_attack_up_down(int keycode, t_param *maps)
{
if (maps->waitting_attack == 1 && keycode == KEY_UP)
{
if (maps->map[maps->user.x - maps->win_width - 1] == 'L' || \
maps->map[maps->user.x - maps->win_width - 1] == 'R')
maps->map[maps->user.x - maps->win_width - 1] = '0';
// 공격범위 안에 enemy가 있으면 없에버린다
maps->user.direction = 3; // 플레이어 방향 변경
maps->check_attack = 3; // 공격모션 방향 변경
maps->waitting_attack = 0; // 공격대기 초기화
return (1);
}
if (maps->waitting_attack == 1 && keycode == KEY_DOWN)
{
if (maps->map[maps->user.x + maps->win_width + 1] == 'L' || \
maps->map[maps->user.x + maps->win_width + 1] == 'R')
maps->map[maps->user.x + maps->win_width + 1] = '0';
maps->user.direction = 4;
maps->check_attack = 4;
maps->waitting_attack = 0;
return (1);
}
return (0);
}
입력된 방향에 맞춰서 해당 위치의 맵에 무슨요소가 있는지 확인하여 이동시켜준다
void move_map(int keycode, t_param *maps)
{
if (move_land(keycode, maps))
{
maps->move_cnt += 1;
ft_printf("%d\n", maps->move_cnt);
}
if (move_chase(keycode, maps))
{
maps->move_cnt += 1;
maps->collection -= 1; // collection 갯수를 하나 줄여준다
ft_printf("%d\n", maps->move_cnt);
}
if (move_potal(keycode, maps))
{
maps->move_cnt += 1;
ft_printf("%d\n", maps->move_cnt);
exit(0);
}
if (check_enemy(keycode, maps)) // 해당위치에 적이 있으면 게임을 종료시킨다
exit(0);
check_enemy2(maps); // 적의 공격범위안에 들어왔는지 검사한다
enemy_set(maps); // 맵에 있는 적들을 이동시켜준다
maps->waitting_attack = 0;
}
이동하는 위치가 빈땅(0)이면 user_move를 호출한다
int move_land(int keycode, t_param *maps)
{
if (keycode == KEY_UP && \
(maps->map)[maps->user.x - maps->win_width - 1] == '0')
{
user_move(maps, 1);
return (1);
}
else if (keycode == KEY_DOWN && \
(maps->map)[maps->user.x + maps->win_width + 1] == '0')
{
user_move(maps, 2);
return (1);
}
else if (keycode == KEY_LEFT && (maps->map)[maps->user.x - 1] == '0')
{
user_move(maps, 3);
return (1);
}
else if (keycode == KEY_RIGHT && (maps->map)[maps->user.x + 1] == '0')
{
user_move(maps, 4);
return (1);
}
return (0);
}
flag에 맞춰서 해당위치를 플레이어로 바꾸고 기존 플레이어 위치를 빈땅으로 변경한다
void user_move(t_param *maps, int flag)
{
if (flag == 1)
{
(maps->map)[maps->user.x] = '0';
(maps->map)[maps->user.x - maps->win_width - 1] = 'P';
}
else if (flag == 2)
{
(maps->map)[maps->user.x] = '0';
(maps->map)[maps->user.x + maps->win_width + 1] = 'P';
}
else if (flag == 3)
{
(maps->map)[maps->user.x] = '0';
(maps->map)[maps->user.x - 1] = 'P';
}
else if (flag == 4)
{
(maps->map)[maps->user.x] = '0';
(maps->map)[maps->user.x + 1] = 'P';
}
}
maps->collection이 0인지 확인하여 수집품이 다 모아진 상태에서만 이동이 가능하게 조건을 추가로 지정했다
int move_potal(int keycode, t_param *maps)
{
if (keycode == KEY_UP && (maps->map)[maps->user.x - maps->win_width - 1] \
== 'E' && maps->collection == 0)
return (1);
else if (keycode == KEY_DOWN && (maps->map)[maps->user.x + \
maps->win_width + 1] == 'E' && maps->collection == 0)
return (1);
else if (keycode == KEY_LEFT && \
(maps->map)[maps->user.x - 1] == 'E' && maps->collection == 0)
return (1);
else if (keycode == KEY_RIGHT && \
(maps->map)[maps->user.x + 1] == 'E' && maps->collection == 0)
return (1);
return (0);
}
유저가 이동한 위치에 enemy가 있으면 1을 반환하여 게임을 종료시킨다
int check_enemy(int keycode, t_param *maps)
{
if (keycode == KEY_UP && \
((maps->map)[maps->user.x - maps->win_width - 1] == 'R' || \
(maps->map)[maps->user.x - maps->win_width - 1] == 'L'))
return (1);
else if (keycode == KEY_DOWN && \
((maps->map)[maps->user.x + maps->win_width + 1] == 'R' || \
(maps->map)[maps->user.x + maps->win_width + 1] == 'L'))
return (1);
else if (keycode == KEY_LEFT && ((maps->map)[maps->user.x - 1] == 'R' || \
(maps->map)[maps->user.x - 1] == 'L'))
return (1);
else if (keycode == KEY_RIGHT && ((maps->map)[maps->user.x + 1] == 'R' || \
(maps->map)[maps->user.x + 1] == 'L'))
return (1);
return (0);
}
유저가 이동한 범위가 적의 공격범위 (적 좌우 한칸)안에 들어간 경우 게임을 종료시킨다
void check_enemy2(t_param *maps)
{
int i;
i = 0;
while (maps->map[i])
{
if (maps->map[i] == 'L' || maps->map[i] == 'R')
{
if (maps->map[i - 1] == 'P')
exit(0);
else if (maps->map[i + 1] == 'P')
exit(0);
}
i++;
}
}
맵에 존재하는 enemy들을 랜덤하게 이동시킨다
void enemy_set(t_param *maps)
{
int i;
i = 0;
while (maps->map[i])
{
if (maps->map[i] == 'R' || maps->map[i] == 'L') // 해당위치가 enemy이면
enemy_move(maps, i); // enemy 이동
i++;
}
i = 0;
while (maps->map[i])
{
if (maps->map[i] == 'r')
// enemy가 여러칸을 한번에 이동하는것을 방지하고자
// 이동중에는 소문자로 표시하고 이동이 종료되면 대문자로 변경
maps->map[i] = 'R';
else if (maps->map[i] == 'l')
maps->map[i] = 'L';
i++;
}
}
void enemy_move(t_param *maps, int enemy_position)
{
int keycode;
int cnt;
cnt = 0;
while (1)
{
keycode = (rand() % 4) + 123; // rand함수로 상하좌우 이동을 정한다
if (keycode == KEY_UP && \
(maps->map)[enemy_position - maps->win_width - 1] == '0')
// 해당하는 위치가 빈땅이면 enemy를 이동시킨다
return (move_enemy(maps, 1, enemy_position));
else if (keycode == KEY_DOWN && \
(maps->map)[enemy_position + maps->win_width + 1] == '0')
return (move_enemy(maps, 2, enemy_position));
else if (keycode == KEY_LEFT && (maps->map)[enemy_position - 1] == '0')
return (move_enemy(maps, 3, enemy_position));
else if (keycode == KEY_RIGHT && (maps->map)[enemy_position + 1] == '0')
return (move_enemy(maps, 4, enemy_position));
cnt++;
if (cnt == 10) // 10번 반복할 동안 이동이 안 이루어졌으면 종료시킨다
return ;
}
}