일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 이지스퍼블리싱
- c#
- 리뷰
- c
- Kotlin
- 김성엽
- 알고리즘
- VS ERROR
- Programming
- 배열
- 연산자
- 함수
- CS
- doit코틀린프로그래밍
- Tips프로그래밍강좌
- Direct2D
- c++
- Tips강좌
- 지식나눔강좌
- Windows
- Visual Studio
- tipssoft
- Desktop
- 티스토리
- 문법
- 포인터
- 프로그래밍
- 백준
- Javascript
- Win32
- Yesterday
- Today
- Total
F.R.I.D.A.Y.
물리엔진 - 점프 구현하기 본문
이전 시간에는 캐릭터가 바닥을 만났을 때, 더이상 아래로 내려가지 않도록 했습니다. 이번에는 점프를 구현해보겠습니다.
점프 구현
단순히 만들면 그냥 키 입력을 받았을 때 이동속도로 음수(-)값을 주면 됩니다. 근데, 이러면 다시 점프가 가능해지죠. 그래서 우리는 키 상태를 저장하고 실 계산은 Calculate 메서드에서 처리하도록 구성할겁니다.
키 상태를 저장하는 방법은 아래 포스트를 참고하세요.
위 페이지의 정보대로 참고하면 키 상태를 저장하는 변수[# 이 포스트에서 변수명은 keyState입니다.]와 OnKeyDown, OnKeyUp 메서드가 생성되었을 것입니다.
LRESULT MainWindow::OnKeyDown(WPARAM key)
{
keyState[key] = true;
return 0;
}
LRESULT MainWindow::OnKeyUp(WPARAM key)
{
keyState[key] = false;
return 0;
}
경우에 따라선 여러 번 점프하는 것을 만들 수 있겠지만, 지금은 한 번만 점프가 가능한 것으로 만들겠습니다. MainWindow의 멤버 메서드로 bool 타입의 변수 하나를 생성해줍니다.
bool keyState[256];
bool canJump = false;
기존 Calculate 메서드입니다.
void MainWindow::Calculate()
{
static float gravity = 3.f;
static float dropSpeed = 0.f;
dropSpeed += gravity; // 여기부터
if (dropSpeed >= 0.f) {
for (size_t i = 0; i < 3; ++i) {
if (!(ground[i].left < rcCenter.x + rcSize.width/ 2.f &&
rcCenter.x - rcSize.width / 2.f < ground[i].right)) continue;
if (ground[i].top < rcCenter.y + rcSize.height / 2) continue;
if (abs(ground[i].top - rcCenter.y - rcSize.height / 2) < 0.001f) {
dropSpeed = 0.f;
break;
}
if (rcCenter.y + rcSize.height / 2 + dropSpeed > ground[i].top) {
float gap = ground[i].top - rcCenter.y - rcSize.height / 2.f;
dropSpeed = gap;
}
}
}
rcCenter.y += dropSpeed;
}
표시된 부분부터 코드 수정을 진행하겠습니다.
점프를 하기 위해선 일단 반발력을 가질 수 있는 벽에 위치한지를 알아야하고, 점프를 취하는 키가 눌린 상태인지를 알아야합니다. 지금 상태에선 바닥에 위치한 상태를 canJump 변수가 가지고 있다고 생각하겠습니다. 그럼 아래와 같은 판정식을 만들 수 있습니다.
if(canJump && keyState[VK_SPACE]){
}else{
}
생각해봅시다. 우리가 점프를 하면 속도의 변화는 어떤 그래프를 가지나요? 아마도 COS(θ)[# θ는 0 ~ π/2]와 유사한 그래프를 그릴겁니다. 즉, 가속은 땅을 박차고 오를 때 한 번 뿐입니다. 따라서 코드를 작성할 때도 가속을 한 번만 해주면 되는거죠. 다시 점프하면 안되니까 이 과정을 하면 canJump는 false로 전환해주고요.
if(canJump && keyState[VK_SPACE]){
dropSpeed = -30.f;
canJump = false;
}else{
dropSpeed += gravity;
}
그리고 점프를 했으면 이젠 떨어지도록 중력 가속도를 더해줍니다. 이렇게만 하면 프로그램 시작 후 한 번만 점프할 수 있습니다. 바닥을 만났으면 다시 점프할 수 있도록 아래 분기문에 추가해줍니다.
if (abs(ground[i].top - rcCenter.y - rcSize.height / 2) < 0.001f) {
dropSpeed = 0.f;
canJump = true; // 추가
break;
}
결과
이렇게 코드를 따라하면 아래와같이 반복 점프가 가능해졌습니다.
아래는 변경된 Calculate 메서드의 전문입니다.
void MainWindow::Calculate()
{
static float gravity = 4.3f;
static float dropSpeed = 0.f;
if (canJump && keyState[VK_SPACE]) {
dropSpeed = -30.f;
canJump = false;
}
else {
dropSpeed += gravity;
}
if (dropSpeed >= 0.f) {
for (size_t i = 0; i < 3; ++i) {
if (!(ground[i].left < rcCenter.x + rcSize.width/ 2.f &&
rcCenter.x - rcSize.width / 2.f < ground[i].right)) continue;
if (ground[i].top < rcCenter.y + rcSize.height / 2) continue;
if (abs(ground[i].top - rcCenter.y - rcSize.height / 2) < 0.001f) {
dropSpeed = 0.f;
canJump = true;
break;
}
if (rcCenter.y + rcSize.height / 2 + dropSpeed > ground[i].top) {
float gap = ground[i].top - rcCenter.y - rcSize.height / 2.f;
dropSpeed = gap;
}
}
}
rcCenter.y += dropSpeed;
}
더 생각해보기
현재 코드에서는 캐릭턱 공중에 있더라도 착지하지 않은 상황이라면 공중에서 한 번 뛸 수 있습니다. 일부러 공중에서도 점프가 가능하도록 한 번은 허용하는 방식으로 게임을 구현하는 분들도 계시지만, 그렇지 않은 경우도 있죠.
어떻게 하면 공중인 경우엔 점프를 하지 못하도록 구성할 수 있을까요? 한번 생각해보세요. 댓글로 코드를 입력하면 제가 생각한 것과 같은 답인지 답글 달겠습니다.
# index
'DEV > Direct2D' 카테고리의 다른 글
물리엔진 - 벽 충돌 part2. 좌우 벽 구현 (0) | 2021.05.14 |
---|---|
물리엔진 - 좌우 이동 (0) | 2021.05.14 |
물리엔진 - 벽 충돌 part1. 바닥 구현 (0) | 2021.05.11 |
물리엔진 - 중력 구현 안정화 (0) | 2021.05.10 |
물리엔진 - 중력 구현 (0) | 2021.05.10 |