개요


42과제인 transendence를 진행하면서 구현한 Pong game을 정리해보려한다. 간단한 게임이지만 생각보다 고려해야할 지점이 몇 가지 있었고 주로 고민했던 포인트들은 다음과 같다.

지금 생각해보면, 전부 간단하게 벡터간의 충돌을 계산함으로써 쉽게 해결할 수 있는 문제들이긴 했다.

기존 방법


처음 pong 게임을 구현한 방식은 ball의 위치, 방향, 크기를 각각 정의하고 한번의 연산마다 ball의 크기를 조정하여, paddle의 위치를 기반으로 충돌을 계산하는 방식을 사용했었다.

이때 연산되는 시간이 일정하지 않을 경우, 공이 빨라지거나 느려지는 현상이 있었다.

또한 충돌을 계산하는 방식이 한번에 연산에 이루어지다 보니, 공이 다음 연산에서 패들을 넘어갈 경우 이를 감지하지 못하는 일이 발생했다. 공이 빠른 속도로 움직이거나, 연산 사이의 과정이 너무 길 경우 해당 문제들이 일어났다.

마지막으로 충돌이 일어날 때, 공이 패들을 조금 파고들어간 후에, 충돌을 감지하는 일이 빈번하게 일어났다. 그렇다고 충돌을 미리 감지하고 방향을 바꾸기에는 패들에 닿지 않았는데도 공이 튕겨지는 듯한 연산이 일어났다.

해결방법


각 연산을 일정하게 보장하기 위해서 delta값을 정의하고 해당 값을 각각의 크기에 곱해줌으로써 일정한 속도를 보장했다.

예시:

/* delta 값 계산*/
{
	...
	let delta = (timeStamp - data.lastTime) / 1000.0;
	update(delta);
	render();
	data.lastTime = timeStamp;
}

/* 공의 움직임 */
static calculateBallPosition(ball: Ball, delta: number, factor: number) : vec2 {
    let tempVec2 = vec2.create();
    vec2.add(tempVec2, ball.position, vec2.scale(tempVec2, ball.direction, ball.velocity * delta));
    return tempVec2;
}

/* 패들의 움직임 */
if (data.keyPress.up) {
    paddle[0].position[1] += paddle[0].paddleSpeed * delta
} else if (data.keyPress.down) {
    paddle[0].position[1] -= paddle[0].paddleSpeed * delta;
} else {
    paddle[0].position[1] += 0;
}

충돌 로직의 불완전함을 보완하기 위해서 두 벡터간의 충돌을 계산하는 식을 사용했다. 전자를 공에 대한 벡터의 방정식, 후자를 패들에 대한 방정식으로 설정하고, 이를 풀어서 계산해보면