경일게임아카데미 프로그래밍반 28기 21일차 수업과제 (2021. 05. 07)
오늘은 WIN32 API을 활용하여 각도를 조절하여 총알을 발사해봅시다!
과제1 - 대포의 포선 각도를 자유자제로 조절하고 각도에 따라 미사일을 나오는 대포를 제작해보세요.
조건.
1. 화면 하단에 반원을 제작하세요.
2. 미사일을 발사할 선을 그리세요.
3. 선의 각도는 키보드를 통해 움직이게 하세요.
4. 스페이스바를 눌러 미사일을 발사하도록 하세요.
5. 이때 발사하는 미사일의 각도는 발사대의 각도와 동일하게 하세요.
6. 미사일이 맵 밖으로 나가면 그냥 사라지게 하세요.
playGround.h 소스코드
#pragma once
#include "gameNode.h"
#define PI 3.14156f
#define BULLETMAX 3
struct tagObj
{
POINT center; // 대포 중점 좌표 초기화
POINT endPoint; // 대포 끝점 좌표 초기화
int radius; // 대포 반지름 초기화
int length; // 대포 길이 초기화
float angle; // 대포 각도 초기화
};
struct tagBullet
{
float x, y; // 총알 중점 좌표 초기회
float speed; // 총알 속도 초기화
float angle; // 총알 각도 초기화
float radius; // 총알 반지름 초기화
bool isFire; // 총알 발사 여부 초기화
};
class playGround : public gameNode
{
private:
tagObj _obj; // 대포를 객체로(obj)라는 별명으로 설정
tagBullet _bullet[BULLETMAX]; // 미사일을 bullet라는 별명으로 설정
public:
playGround();
~playGround();
virtual HRESULT init();
virtual void release();
virtual void update();
virtual void render(HDC hdc);
void bulletFire();
void bulletMove();
};
playGround.cpp 소스코드
#include "stdafx.h"
#include "playGround.h"
playGround::playGround()
{
}
playGround::~playGround()
{
}
//초기화는 여기다 하세요 제발
HRESULT playGround::init()
{
gameNode::init();
// 캐논 초기화
_obj.angle = PI / 2; // 캐논의 각도 설정
_obj.length = 100; // 캐논의 길이 설정
_obj.radius = 100; // 캐논의 반지름 설정
_obj.center.x = WINSIZEX / 2; // 캐논의 시작점 X 설정
_obj.center.y = WINSIZEY; // 캐논의 시작점 Y 설정
// 미사일 초기화
for (int i = 0; i < BULLETMAX; i++)
{
_bullet[i].speed = 5; // 총알 스피드 설정
_bullet[i].radius = 20; // 총알 반지름 설정
_bullet[i].isFire = false; // 총알 발사 여부 설정
}
return S_OK;
}
//메모리 해제는 여기다 하세요 제발
void playGround::release()
{
gameNode::release();
}
//여기에다 연산하세요 제에발
void playGround::update()
{
gameNode::update();
// 대포의 끝점 X, Y 설정
_obj.endPoint.x = cosf(_obj.angle) * _obj.length + _obj.center.x;
_obj.endPoint.y = -sinf(_obj.angle) * _obj.length + _obj.center.y;
// 왼쪽, 오른쪽, 발사 키보드를 누를 때
if (KEYMANAGER->isStayKeyDown(VK_LEFT) && _obj.angle <= 3.0) // 누름 여부 및 각도 제한
_obj.angle += 0.04f;
if (KEYMANAGER->isStayKeyDown(VK_RIGHT) && _obj.angle > 0.15) // 누름 여부 및 각도 제한
_obj.angle -= 0.04f;
if (KEYMANAGER->isOnceKeyDown(VK_SPACE)) // 누름 여부
bulletFire(); // 총알 발사
// 총알 움직임
bulletMove();
}
//여기에다 그려라 좀! 쫌!
void playGround::render(HDC hdc)
{
HDC backDC = this->getBackBuffer()->getMemDC();
PatBlt(backDC, 0, 0, WINSIZEX, WINSIZEY, WHITENESS);
// 위에 건들지마라
//================제발 이 사이에 좀 그립시다==========================
EllipseMakeCenter(backDC, _obj.center.x, _obj.center.y, 100, 100); // 대포 원 출력
LineMake(backDC, _obj.center.x, _obj.center.y, _obj.endPoint.x, _obj.endPoint.y); // 대포 포선 길이 출력
// 총알 출력
for (int i = 0; i < BULLETMAX; i++)
{
if (!_bullet[i].isFire) continue;
EllipseMakeCenter(backDC, _bullet[i].x, _bullet[i].y, _bullet[i].radius * 2, _bullet[i].radius * 2);
}
//==================================================
//여기도 건들지마라
this->getBackBuffer()->render(hdc, 0, 0);
}
// 총알 발사 함수
void playGround::bulletFire()
{
for (int i = 0; i < BULLETMAX; i++)
{
if (_bullet[i].isFire) continue;
_bullet[i].isFire = true;
_bullet[i].x = cosf(_obj.angle) * (_obj.length + 5) + _obj.center.x;
_bullet[i].y = -sinf(_obj.angle) * (_obj.length + 5) + _obj.center.y;
_bullet[i].angle = _obj.angle;
break;
}
}
// 총알 움직임 함수
void playGround::bulletMove()
{
for (int i = 0; i < BULLETMAX; i++)
{
if (!_bullet[i].isFire) continue;
_bullet[i].x += cosf(_bullet[i].angle) * _bullet[i].speed;
_bullet[i].y += -sinf(_bullet[i].angle) * _bullet[i].speed;
// 화면 바깥으로 나갈 경우 나갈수 있는 총알 개수 초기화 (순서 : 상, 좌우(같이))
if (_bullet[i].y + _bullet[i].radius < 0)
_bullet[i].isFire = false;
// 좌 OR 우
if (_bullet[i].x + _bullet[i].radius < 0 || _bullet[i].x + _bullet[i].radius > WINSIZEX)
_bullet[i].isFire = false;
}
}
어떻게 구현해야 할까?
조건.
1. 화면 하단에 반원을 제작하세요.
2. 미사일을 발사할 선을 그리세요.
3. 선의 각도는 키보드를 통해 움직이게 하세요.
4. 스페이스바를 눌러 미사일을 발사하도록 하세요.
5. 이때 발사하는 미사일의 각도는 발사대의 각도와 동일하게 하세요.
6. 미사일이 맵 밖으로 나가면 그냥 사라지게 하세요.
먼저 조건을 다시 확인하여 어떻게 구현해야 할 지 생각해보자.
- 먼저 화면 하단에 반원을 제작하자!
- 그리고 미사일을 발사할 선(포선)을 그리자.
- 선의 각도는 키보드를 통해 움직이게 해야하니 VK_LEFT, VK_RGIHT를 사용하자.
- 스페이스바를 눌러 미사일을 발사하도록 해야 하니 VK_SPACE를 사용하자 이때 미사일 발사는 슈팅 베이직!을 활용하면 된다.
- 이때 발사하는 미사일의 각도는 발사대의 각도와 동일하게 하세요.
(얘가 문제다.. 어떻게 처리해야 할까? 😱) - 미사일이 맵 밖으로 나가면 그냥 사라지게 하세요.
마찬가지로 isFire를 false 처리하면 될 것 같다.
로직은?
- 반원은 원을 그리지만 원의 하단부를 그냥 화면 단에서 잘라버리면 된다.
- 이후 LineMake를 통해 선을 그려준다.
- 키보드를 이용하는 건 쉬우니 LEFT와 RIGHT를 이용할 때 앵글값을 바꿔주자.
- 총알 발사 스페이스 SPACE를 누르면 미사일이 나가야 하므로 슈팅 베이직! bulletFire를 재사용하자
- 얘를 어떻게 해야할까.. 😕
- bulletMove를 이용하여 제작하되 화면 바깥으로 나갔을 경우를 if문으로 처리하여 isFire를 false로 바꿔주자.
과제를 하면서 겪은 문제점
대포의 끝점(X,Y)를 어떻게 줘야 할지 몰라서 많은 생각을 했다.
해당 영상 말고도 코드를 이리 저리 수정할떄마다 포신이 엿가락 처럼 추욱- 늘어지질 않나 길이가 여의봉 처럼 마음대로 늘었다 줄었다. 하는 문제점이 있었다.
// 대포의 끝점 X, Y 설정
_obj.endPoint.x = cosf(_obj.angle) * _obj.center.x;
_obj.endPoint.y = -sinf(_obj.angle) * _obj.center.y;
분명 이 부분을 수정하면 될 거 같은데 여기를 어떻게 수정해줘야하는지 모르겠다.
나를 포함한 대부분의 동기생들이 저렇게 길이가 길어져있거나 길이가 마음대로 늘어났다 줄어났다고 한다. 🤣
결국 선생님꼐서 한자리에 모아서 알려주셔서 해결했다.
문제점은 포신의 길이를 넣어주지 않았던 것.
// 대포의 끝점 X, Y 설정
_obj.endPoint.x = cosf(_obj.angle) * _obj.length + _obj.center.x;
_obj.endPoint.y = -sinf(_obj.angle) * _obj.length + _obj.center.y;
위 코드에서 가운데에 포신의 길이만 쏘-옥 넣어주면 문제가 해결됐다.
그렇다면 어떻게 해결된걸까? 😑
내가 짠 코드를 보면 앵글값을 COS한 상태와 -SIN한 상태에서 지속적으로 포신의 중점좌표 X, Y값을 곱해주고 있어서 당연히 저런 문제가 생길 수 밖에 없었던 것이다.
가운데에 포선의 길이를 걸어주니 COS한 상태와 -SIN 상태에 포신의 길이만큼 곱하여 설정하고 이를 중점좌표 X, Y를 더해주면 포선의 길이가 원래 설정한 길이만큼 설정이 되므로 길게 늘어나는 문제가 해결 되는 것이다.
돌이켜 생각해보면 정말 정말 쉬운 문제였는데 왜 그 때 당시엔 생각하지 못했을까.. 😵
최종_진짜 결과화면
코드를 수정해주니 문제 없이 잘 돌아간다 ^_^
개인적으로 해보고 싶은 심화학습
총알들이 바깥으로 나갈 때 벽에 충돌되고 다시 안으로 튕겨나오는 걸 하고 싶었지만 선생님께서 그 부분은 "내일 한다." 말씀해주셔서 딱히 없었다!
아쉬운점
포선의 끝점 X / Y축의 값을 구하는게 참 어려웠다. 결과화면에서야 이쁘게 나왔지만 그 전까지는 왼쪽이나 오른쪽으로 갈 때 엿가락 마냥 쭈우욱- 늘어지는 문제점이 있었다.
불행 중 다행일까? 나 뿐만 아니라 동기들도 나와 같은 문제점이 있었다. 선생님께서 우리를한데 모아 확인해주시고 바람직하게 고쳐주셨다. 물론 이해는 덧붙이며! 😎
'학원 > 경일게임아카데미' 카테고리의 다른 글
39. 스물두번째 수업과제 [포물선 미리보기 그리기] (0) | 2023.01.14 |
---|---|
38. 스물두번째 수업 (0) | 2023.01.13 |
36. 스물한번째 수업 - 2 (0) | 2023.01.13 |
35. 스물한번째 수업 (0) | 2023.01.13 |
34. 스무번째 수업과제 [원과 사각형의 충돌] (0) | 2023.01.13 |