첫 번째 방식
ESC 키
mlx_hook(tools->win_ptr, X_EVENT_KEY_EXIT, 0, &finish_cub3d, tools);
mlx를 끝낼 수 있는 finish_cub3D라는 함수를 만들었다.
finish_cub3D애서 할당을 해제해주고, exit을 해준다.
회전변환
방향키의 왼쪽, 오른쪽을 눌렀을 때 실행되게 해야 한다.
따라서 우선적으로 회전행렬을 이용해 방향벡터와 카메라벡터를 돌려준다.
처음에 생각했던 건 다음과 같다.
(회전각이 작아질수록 움직임이 더 부드러워진다)
def matrix(vec) :
newx = cos(alpha) * vec.x - sin(alpha) * vec.y
newy = sin(alpha) * vec.x + cos(alpha) * vec.y
vec.x = newx
vec.y = newy
return vec
def rotation(tools, keycode):
if keycode == LEFT_TURN:
tools.alpha += -(PI / 36) # += 말고 그냥 =으로 해야
else if keycode == RIGHT_TURN:
tools.alpha += (PI / 36) # += 말고 그냥 =으로 해야
matrix(tools.dir, tools.alpha)
matrix(tools.dir, tools.alpha)
이 경우 회전이 부정확해 보인다.
문제 : 회전각이 점점 더해지고 더해지는 것.
- 내가 움직이는 것이 아닌 축을 기준으로 잡아야
- 따라서 매번 회전각을 더해주는 것이 절대 아니다
- 즉, 한번 회전 후 0으로 초기화된다고 생각하자.
이동
처음에 생각했던 이동은 다음과 같다.
- 상, 하 : pos의 x를 변화시킨다.
- 좌, 우 : pos의 y를 변화시킨다.
이러면 고개를 돌렸는데 해당 방향 기준으로 상하좌우 이동이 안된다.
따라서 방향벡터를 이용해야 한다. (각도를 이용하는 방법도 있지만…여기선 생략)
// 앞으로 갈 때
new_x = pos->x + dir->x * VELOCITY;
new_y = pos->y + dir->y * VELOCITY;
// 뒤로 갈 때
new_x = pos->x - dir->x * VELOCITY;
new_y = pos->y - dir->y * VELOCITY;
// 왼쪽으로 갈 때
new_x = tools->pos.y - tools->dir.x * VELOCITY;
new_y = tools->pos.x + tools->dir.y * VELOCITY;
// 오른쪽으로 갈 때
new_x = tools->pos.y + tools->dir.x * VELOCITY;
new_y = tools->pos.x - tools->dir.y * VELOCITY;
렌더링
그림을 그리는 과정에서 깜박임을 해결하기 위한 부분.
while(1):
if keyhook == ARROW_KEYS
action()
if keyhook == ESC:
destroy_window()
finish()
drawing()
mlx에서 while의 역할을 해주는 것 : mlx_hook()
while문 안에 코드 : mlx_loop_hook()
두 번째 방식
이렇게 하니 너무 끊김이 심해서 바꾼 방식
-
키를 press하고, 키와 관련된 변수를 바꾼다.
(ft_key_press) -
키를 release하고, 키와 관련된 변수를 바꾼다.
(ft_key_release) -
mlx_loop_hook()안에 이동 관련 함수(ft_event)를 만든다.이동 관련 함수에는 키와 관련된 변수를 통해 이동을 조정한다.
int main()
{
mlx_hook(tools->win_ptr, X_EVENT_KEY_PRESS, 1L << 1, &ft_key_press, tools);
mlx_hook(tools->win_ptr, X_EVENT_KEY_RELEASE, 1L << 0, &ft_key_release, tools);
mlx_hook(tools->win_ptr, X_EVENT_KEY_EXIT, 0, &finish_cub3d, tools);
mlx_loop_hook(tools->mlx_ptr, &ft_event, tools);
mlx_loop(tools->mlx_ptr);
}
키를 press, release하는 함수는 다음과 같다.
이를 mlx_hook()과 연결시켜 놓는다.
int ft_key_press(int keycode, t_box *tools)
{
if (keycode == 53)
{
mlx_destroy_window(tools->mlx_ptr, tools->win_ptr);
finish_cub3d(tools);
}
if (keycode == LEFT_TURN)
tools->left_turn = 1;
else if (keycode == RIGHT_TURN)
tools->right_turn = 1;
if (keycode == FORWARD_MOVE)
tools->forward_move = 1;
else if (keycode == BACKWARD_MOVE)
tools->backward_move = 1;
if (keycode == LEFT_MOVE)
tools->left_move = 1;
else if (keycode == RIGHT_MOVE)
tools->right_move = 1;
return (0);
}
int ft_key_release(int keycode, t_box *tools)
{
if (keycode == LEFT_TURN)
tools->left_turn = 0;
else if (keycode == RIGHT_TURN)
tools->right_turn = 0;
if (keycode == FORWARD_MOVE)
tools->forward_move = 0;
else if (keycode == BACKWARD_MOVE)
tools->backward_move = 0;
if (keycode == LEFT_MOVE)
tools->left_move = 0;
else if (keycode == RIGHT_MOVE)
tools->right_move = 0;
return (0);
}
실제 이동을 담당하는 ft_event()는 다음과 같다.
static void move_pos(t_box *tools, t_vec_f *pos, t_vec_f *new)
{
if (tools->total_map[(int)pos->y][(int)new->x] == 0)
pos->x = new->x;
if (tools->total_map[(int)new->y][(int)pos->x] == 0)
pos->y = new->y;
}
void ft_move_key(t_box *tools, t_vec_f *pos, t_vec_f *dir, t_vec_f *new)
{
if (tools->forward_move == 1)
{
new->x = pos->x + dir->x * VELOCITY;
new->y = pos->y + dir->y * VELOCITY;
}
else if (tools->backward_move == 1)
{
new->x = pos->x - dir->x * VELOCITY;
new->y = pos->y - dir->y * VELOCITY;
}
else if (tools->left_move == 1)
{
new->x = pos->x + dir->y * VELOCITY;
new->y = pos->y - dir->x * VELOCITY;
}
else if (tools->right_move == 1)
{
new->x = pos->x - dir->y * VELOCITY;
new->y = pos->y + dir->x * VELOCITY;
}
move_pos(tools, pos, new);
}
int ft_event(t_box *tools)
{
t_vec_f new;
new.x = 0;
new.y = 0;
if (tools->left_turn == 1 || tools->right_turn == 1)
rotation(tools);
if (tools->forward_move == 1 || tools->backward_move == 1 || \
tools->left_move == 1 || tools->right_move == 1)
ft_move_key(tools, &tools->pos, &tools->dir, &new);
drawing(tools);
return (0);
}
단, 이 경우 키를 오래 누르면 매끄럽게 움직이나 키를 가볍게 누르면 프레임이 변화하지 않는다.
따라서 키를 누르는 함수 안에도 ft_event()를 넣어서 루프 안에서 실행하거나 키를 누른 상황에서나 모두 그림이 출력되도록 한다.
키를 누른 상황에서 그림이 출력되면 연산이 중복되는 게 아닌가 싶지만, 오버헤드가 그렇게 크지 않을 것이다.
<수정된 ft_key_press()>
int ft_key_press(int keycode, t_box *tools)
{
if (keycode == 53)
{
mlx_destroy_window(tools->mlx_ptr, tools->win_ptr);
finish_cub3d(tools);
}
if (keycode == LEFT_TURN)
tools->left_turn = 1;
else if (keycode == RIGHT_TURN)
tools->right_turn = 1;
if (keycode == FORWARD_MOVE)
tools->forward_move = 1;
else if (keycode == BACKWARD_MOVE)
tools->backward_move = 1;
if (keycode == LEFT_MOVE)
tools->left_move = 1;
else if (keycode == RIGHT_MOVE)
tools->right_move = 1;
ft_event(tools); // 이 부분을 추가해 가볍게 키를 쳤을때도 렌더링이 되도록 한다.
return (0);
}