경일게임아카데미 프로그래밍반 28기 20일차 수업과제 (2021. 05. 06)
오늘은 WIN32 API을 활용하여 원과 원의 충돌을 제작해봅시다!
과제1 - 원과 원의 충돌을 제작해보세요.
조건.
1. 원 하나는 화면 중앙에 위치한다.
2. 또 다른 사용자의 원은 마우스로 움직인다.
3. 두 원이 충돌하면 화면 중앙 원을 색칠시킨다.
playGround.h 소스코드
#pragma once
#include "gameNode.h"
class playGround : public gameNode
{
private:
// 초기화
RECT _user_Ellipse; // 사용자 원
float _user_radius; // 사용자 원 반지름
RECT _center_Ellipse; // 가운데 원
float _center_Ellipse_x; // 가운데 원 X축 중점 좌표
float _center_Ellipse_y; // 가운데 원 Y축 중점 좌표
float _center_Ellipse_radius; // 가운데 원 반지름
float _distance_x; // 가운데 원 중점 X 좌표 - 사용자 원 중점 X 좌표 값
float _distance_y; // 가운데 원 중점 Y 좌표 - 사용자 원 중점 Y 좌표 값
float _hypo; // 빗변
bool _iscrash; // 충돌여부
public:
playGround();
~playGround();
virtual HRESULT init();
virtual void release();
virtual void update();
virtual void render(HDC hdc);
};
playGround.cpp 소스코드
#include "stdafx.h"
#include "playGround.h"
playGround::playGround()
{
}
playGround::~playGround()
{
}
//초기화는 여기다 하세요 제발
HRESULT playGround::init()
{
gameNode::init();
// 초기화
_iscrash = false; // 충돌여부
_center_Ellipse = RectMakeCenter(WINSIZEX / 2, WINSIZEY / 2, 300, 300); // 중앙 원
return S_OK;
}
//메모리 해제는 여기다 하세요 제발
void playGround::release()
{
gameNode::release();
}
//여기에다 연산하세요 제에발
void playGround::update()
{
gameNode::update();
_user_Ellipse = RectMakeCenter(_ptMouse.x, _ptMouse.y, 100, 100); // 사용자 원 초기화
_user_radius = (_user_Ellipse.right - _user_Ellipse.left) / 2; // 사용장 원 반지름
_center_Ellipse_x = (_center_Ellipse.left + _center_Ellipse.right) / 2; // 가운데 원 중점 X 좌표
_center_Ellipse_y = (_center_Ellipse.top + _center_Ellipse.bottom) / 2; // 가운데 원 중점 Y 좌표
_center_Ellipse_radius = (_center_Ellipse.right - _center_Ellipse.left) / 2; // 가운데 원 반지름
_distance_x = _center_Ellipse_x - _ptMouse.x; // 가운데 원 중점 X 좌표 - 사용자 원 중점 X 좌표 값
_distance_y = _center_Ellipse_y - _ptMouse.y; // 가운데 원 중점 Y 좌표 - 사용자 원 중점 Y 좌표 값
_hypo = sqrt(_distance_x * _distance_x + _distance_y * _distance_y); // 빗변
/*
-sqrt 함수가 하는일 : 매개변수 x로 들어온 숫자에 루트를 씌워서 계산한 값을 반환해주는 일을 합니다.
즉, 루트 x를 구해주는 함수입니다.를 구해주는 함수입니다. (제곱근을 구해주는 함수)
출처: https://blockdmask.tistory.com/307 [개발자 지망생]
*/
// 충돌여부 판정
if ((_user_radius + _center_Ellipse_radius) >= _hypo)
{
_iscrash = true;
}
else
{
_iscrash = false;
}
}
//여기에다 그려라 좀! 쫌!
void playGround::render(HDC hdc)
{
HDC backDC = this->getBackBuffer()->getMemDC();
PatBlt(backDC, 0, 0, WINSIZEX, WINSIZEY, WHITENESS);
// 위에 건들지마라
//================제발 이 사이에 좀 그립시다==========================
// 사용자 원과 중앙 원 그려주기
Ellipse(backDC, _user_Ellipse);
Ellipse(backDC, _center_Ellipse);
// 충돌일 때 가운데 원 색칠
if (_iscrash)
{
HBRUSH brush1 = CreateSolidBrush(RGB(0, 0, 0));
HBRUSH oldBrush1 = (HBRUSH)SelectObject(backDC, brush1);
Ellipse(backDC, _center_Ellipse);
SelectObject(backDC, oldBrush1);
DeleteObject(brush1);
}
//==================================================
//여기도 건들지마라
this->getBackBuffer()->render(hdc, 0, 0);
}
어떻게 구현해야 할까?
- 화면 중심에 원을 만든다
- 충돌 로직을 구현한다
- 충돌 시 원의 색을 바꿔준다.
로직은?
- 화면 중앙에 원을 만드는건 간단하다
- 유저의 원을 마우스의 x축과 y축을 기점으로 ptMouser를 이용하여 생성해준다.
- 충돌의 자세한 내용은 밑에서 서술하겠다.
- 충돌 시 원의 색을 바꾸는 것은 bool 값을 이용해 충돌일 때만 색을 칠하게 해준다.
충돌
먼저 충돌을 구하기 위해서는 여러 정보가 필요하다.
과제에서 사용자 원은 마우스를 중점으로 움직이기 때문에 사용자 원을 센터 원 바로 옆에 위치시켜서 그림을 그렸다.
user의 원의 반지름 Radius 이하 R은
user.right에서 user.left를 뺀 값에 /2를 해주면 된다.
왜냐하면 user.right에서 user.left를 뺀 값이 원의 지름이므로
/2를 수행하면 반지름을 구할 수 있게 된다.
user의 원의 중점 좌표 X/Y는
중점 좌표 X는 예전부터 구하는 방법을 알고 있다.
user.left에서 user.right를 더한 값에 / 2를 해주면 X축의 중점 좌표이다.
중점 좌표 Y도 동일하다
user.top에서 user.bottom을 더한 값에 / 2를 해주면 Y축의 중점 좌표이다.
나는 원의 반지름 구하는 것을 중점좌표와 헷갈려서 고생을 많이했다. 바보 🤯
중앙에 있는 원 또한 user의 반지름과 중점 좌표를 구한 것처럼 구해주면 된다.
이제 DisX를 구해보자 Dis는 거리를 뜻한다
그렇다면 DisX는 X의 거리를 구한다는 의미인데 이는 위 사진을 보면 이해할 수 있다.
center_x에서 user_x를 빼면 center와 user의 x축의 거리를 구할 수 있다.
마찬가지로 DisY를 구하려면
center_y에서 user_y를 빼면 center와 user의 y축의 거리를 구할 수 있다.
이제 구한 값을 이용해 피타고라스의 정리를 이용해보자
피타고라스의 정리 값은 a^2 + b^2 = c^2 이다.
여기서 우리는 disX^2 + disY^2를 하게 되면 hypo^2를 알수 있다.
이제 여기서 루트를 사용하자. 루트를 사용하면
root(disX * disX + DisY + DisY)는 Hypo가 된다.
이제 마지막으로 충돌이 되었는지 여부를 확인하자
user의 R + center의 R의 값이 hypo보다 크면 충돌이고,
그렇지 않으면 충돌이 아닌 상태이다.
위 소스코드에서 보면
// 충돌여부 판정
if ((_user_radius + _center_Ellipse_radius) >= _hypo)
{
_iscrash = true;
}
else
{
_iscrash = false;
}
이 부분이다.
그렇지만 아래 부분이 이해가 되질 않았다.
if ((_user_radius + _center_Ellipse_radius) >= _hypo)
왜 _user_radius + _center_Ellipse_radius 의 값이 _hypo보다 크면 충돌인가?
혼자서 생각해보다가 더는 모르겠어서 학원에 남아있는 분에게 여쭤보아 알 수 있었다. 😵
사진은 각각 위 왼쪽부터 미충돌, 정확히 충돌, 완전 충돌이다.
실수형에서 정확히 충돌이란 개념이 없겠지만 이는 단순히 이해하기 위해 적은것이다!
결과화면
개인적으로 해보고 싶은 심화학습
원과 원의 충돌이기 때문에 따로 무엇을 심화학습을 할 수 있을까? 생각해보았을 때 없는 것 같다.
아쉬운점
원과 원의 충돌이 머리로는 이해가 되는데 구현하려고 하니 큰 어려움이 뒤 따랐다.
그렇지만 무엇을 하든 기본이 중요하니 어떻게 구현해야 하는지 다시금 생각해보는 시간이 필요하다고 생각했다.
이로인해 글을 작성하면서 다시금 원과 원의 충돌을 보다 자세하게 작성하였다. ☺
'학원 > 경일게임아카데미' 카테고리의 다른 글
35. 스물한번째 수업 (0) | 2023.01.13 |
---|---|
34. 스무번째 수업과제 [원과 사각형의 충돌] (0) | 2023.01.13 |
32. 스무번째 수업 (0) | 2023.01.10 |
31. 열아홉번째 수업 (0) | 2023.01.09 |
30. 열여덟번째 수업과제 [2인용 미사일 게임] (0) | 2023.01.08 |