경일게임아카데미 프로그래밍반 28기 18일차 수업과제 (2021. 05. 03)
오늘은 WIN32 API을 활용하여 2인용 미사일 게임을 제작해봅시다!
과제1 - 슈팅 베이직!을 활용하여 2인용 미사일 게임을 제작하세요
조건.
1. 2인용 게임을 제작해보세요
2. 1/2 player의 움직임, 발사, 총알 모드 변경, 체력게이지, 맵을 구현하세요.
3. 총알 모드는 기본 총알, 5갈래 샷건, 유도탄, 궁극기(자유) 형식으로 만드세요.
4. 1/2 player의 이동은 각자의 맵 안에서만 이동할 수 있도록 구현하세요.
4. 중간 벽을 만드세요.
playGround.h 소스코드
#pragma once
#include "gameNode.h"
#define PLAYER1_BULLETMAX 300
#define PLAYER2_BULLETMAX 300
#define WALL_BULLMAX 600
struct tagBullet
{
int x, y; // 총알 중점용
RECT rc; // 총알 렉트
int speed; // 총알 스피드
bool isFire; // 발사 됐누?
// 210506 추가
int num; // 샷건 전용 변수
};
class playGround : public gameNode
{
private:
// 게임 로직 초기화 & 선언
bool _isStart; // 시작유무
bool _mapchange; // 전장변경
// 210506 추가
int _count; // 샷건 전용 카운트
// 플레이어 관련 변수 & 선언
// Player 1
RECT _player; // 플레이어 1 생성
RECT _player1_backGauge; // 플레이어 1 게이지
RECT _player1_frontGauge; // 플레이어 1 게이지
int _p1_r, _p1_g; // 플레이어 1 게이지 (RGB)
tagBullet _player1_bullet[PLAYER1_BULLETMAX]; // 플레이어 1 총알
RECT _player1_map; // 플레이어 1 맵
int _player1_mode; // 플레이어 1 모드
bool _player1_state; // 플레이어 1 상태
//******************************************************************************
// Player 2
RECT _player2; // 플레이어 2 생성
RECT _player2_backGauge; // 플레이어 2 게이지
RECT _player2_frontGauge; // 플레이어 2 게이지
int _p2_r, _p2_g; // 플레이어 2 게이지 (RGB)
tagBullet _player2_bullet[PLAYER2_BULLETMAX]; // 플레이어 2 총알
RECT _player2_map; // 플레이어 2 맵
int _player2_mode; // 플레이어 2 모드
bool _player2_state; // 플레이어 2 상태
//******************************************************************************
// Wall
RECT _wall; // 벽 생성
float _wall_speed; // 벽 스피드
bool _wall_change; // 벽 방향 전환
//******************************************************************************
// P1 4 SK
RECT _Arbiter; // 아비터
RECT _lockWall; // P2를 잠구는 맵
bool _lockKey; // 움직이는 키 상태값
bool _use4skile; // 1번만 나오게 할 수 있는 상태값
// P2 4 SK
bool _reverseKey; // 키 거꾸로 입력 상태값
public:
playGround();
~playGround();
virtual HRESULT init();
virtual void release();
virtual void update();
virtual void render(HDC hdc);
void bulletFire(); // 총알 발사하는 함수 (P1)
void bulletFire2(); // 총알 발사하는 함수 (P2)
void bulletMove(); // 총알 움직이는 함수 (P1)
void bulletMove2(); // 총알 움직이는 함수 (P2)
void setGauge(); // 총알 맞은 경우 변하는 게이지 (P2)
void setGauge2(); // 총알 맞은 경우 변하는 게이지 (P1)
void player1_mode2(); // Player 1 MODE 2
void player1_mode2_Move(); // Player 1 MODE 2 MOVE
void player2_mode2(); // Player 2 MODE 2
void player2_mode2_Move(); // Player 2 MODE 2 MOVE
void player1_mode3(); // Player 1 MODE 3
void player1_mode3_Move(); // Player 1 MODE 3 MOVE
void player2_mode3(); // Player 2 MODE 3
void player2_mode3_Move(); // Player 2 MODE 3 MOVE
void player1_mode4(); // Player 1 MODE 4
void player1_mode4_Move(); // Player 1 MODE 4 MOVE
void player2_mode4(); // Player 2 MODE 4
};
playGround.cpp 소스코드
#include "stdafx.h"
#include "playGround.h"
playGround::playGround()
{
}
playGround::~playGround()
{
}
// 초기화
HRESULT playGround::init()
{
gameNode::init();
// 게임 로직 초기화 & 선언
_isStart = false;
_lockKey = false;
_use4skile = false;
_reverseKey = false;
_mapchange = false;
// 플레이어 관련 변수 & 선언 (순서 - P1, P2)
_player = RectMakeCenter(WINSIZEX / 2 - 350, WINSIZEY / 2, 100, 50); // Player 1 생성
for (int i = 0; i < PLAYER1_BULLETMAX; i++) // Player 1 총알
{
_player1_bullet[i].x = _player.right + 10;
_player1_bullet[i].y = (_player.top + _player.bottom) / 2;
_player1_bullet[i].rc = RectMakeCenter
(
_player1_bullet[i].x, _player1_bullet[i].y,
20, 20
);
_player1_bullet[i].isFire = false;
_player1_bullet[i].speed = 7;
}
_player1_backGauge = RectMakeCenter(WINSIZEX / 2 - 250, 100, 400, 50); // Player 1 게이지
_player1_frontGauge = RectMakeCenter(WINSIZEX / 2 - 250, 100, 400, 50);
_p1_r = 0;
_p1_g = 240;
_player1_map = RectMake(WINSIZEX / 2 - 450, WINSIZEY / 2 - 250, 400, 600); // Player 1 맵
_player1_mode = 1; // Player 1 모드
_player1_state = true; // Player 1 상태
//******************************************************************************
_player2 = RectMakeCenter(WINSIZEX / 2 + 350, WINSIZEY / 2, 100, 50); // Player 2 생성
for (int i = 0; i < PLAYER2_BULLETMAX; i++) // Player 2 총알
{
_player2_bullet[i].x = _player2.left - 10;
_player2_bullet[i].y = (_player2.top + _player2.bottom) / 2;
_player2_bullet[i].rc = RectMakeCenter
(
_player2_bullet[i].x,
_player2_bullet[i].y,
20, 20
);
_player2_bullet[i].isFire = false;
_player2_bullet[i].speed = 7;
}
_player2_backGauge = RectMakeCenter(WINSIZEX / 2 + 250, 100, 400, 50); // Player 2 게이지
_player2_frontGauge = RectMakeCenter(WINSIZEX / 2 + 250, 100, 400, 50);
_p2_r = 0;
_p2_g = 240;
_player2_map = RectMake (WINSIZEX / 2 + 50, WINSIZEY / 2 - 250, 400, 600); // Player 2 맵
_player2_mode = 1; // Player 2 모드
_player2_state = true; // Player 2 상태
//******************************************************************************
// 벽 관련 변수 & 선언
_wall = RectMake(WINSIZEX / 2 - 15, WINSIZEY / 2 - 250, 30, 100); // 벽 초기화
_wall_speed = 5.0f; // 벽 스피드
_wall_change = false; // 벽 방향 전환
return S_OK;
}
// 메모리 해제
void playGround::release()
{
gameNode::release();
}
// 연산
void playGround::update()
{
gameNode::update();
if (_isStart)
{
// Player 1 움직임
if (KEYMANAGER->isStayKeyDown('W') && _reverseKey == false)
{
_player.top -= 5;
_player.bottom -= 5;
}
if (KEYMANAGER->isStayKeyDown('S') && _reverseKey == false)
{
_player.top += 5;
_player.bottom += 5;
}
if (KEYMANAGER->isStayKeyDown('A') && _reverseKey == false)
{
_player.left -= 5;
_player.right -= 5;
}
if (KEYMANAGER->isStayKeyDown('D') && _reverseKey == false)
{
_player.left += 5;
_player.right += 5;
}
// Player 1 움직임 (R)
if (KEYMANAGER->isStayKeyDown('W') && _reverseKey == true)
{
_player.top += 5;
_player.bottom += 5;
}
if (KEYMANAGER->isStayKeyDown('S') && _reverseKey == true)
{
_player.top -= 5;
_player.bottom -= 5;
}
if (KEYMANAGER->isStayKeyDown('A') && _reverseKey == true)
{
_player.left += 5;
_player.right += 5;
}
if (KEYMANAGER->isStayKeyDown('D') && _reverseKey == true)
{
_player.left -= 5;
_player.right -= 5;
}
// Player 1 맵 충돌 (순서 - 왼, 오, 위, 아래)
if (_player1_map.left >= _player.left)
{
_player.left += 5;
_player.right += 5;
}
if (_player1_map.right <= _player.right)
{
_player.left -= 5;
_player.right -= 5;
}
if (_player1_map.top >= _player.top)
{
_player.top += 5;
_player.bottom += 5;
}
if (_player1_map.bottom <= _player.bottom)
{
_player.top -= 5;
_player.bottom -= 5;
}
// Player 1 총알 발사
if (KEYMANAGER->isOnceKeyDown('Z'))
{
if (_player1_mode == 1)
bulletFire();
if (_player1_mode == 2)
player1_mode2();
if (_player1_mode == 3)
player1_mode3();
if (_player1_mode == 4)
player1_mode4();
}
// Player 1 모드 변경
if (KEYMANAGER->isOnceKeyDown('X'))
{
_player1_mode++;
if (_player1_mode > 4)
{
_player1_mode = 1;
}
}
// Player 2 움직임 (순서 - 왼, 오, 위, 아래)
if (KEYMANAGER->isStayKeyDown('U') && _lockKey == false)
{
_player2.top -= 5;
_player2.bottom -= 5;
}
if (KEYMANAGER->isStayKeyDown('J') && _lockKey == false)
{
_player2.top += 5;
_player2.bottom += 5;
}
if (KEYMANAGER->isStayKeyDown('H') && _lockKey == false)
{
_player2.left -= 5;
_player2.right -= 5;
}
if (KEYMANAGER->isStayKeyDown('K') && _lockKey == false)
{
_player2.left += 5;
_player2.right += 5;
}
// Player 2 맵 충돌
if (_player2_map.left >= _player2.left)
{
_player2.left += 5;
_player2.right += 5;
}
if (_player2_map.right <= _player2.right)
{
_player2.left -= 5;
_player2.right -= 5;
}
if (_player2_map.top >= _player2.top)
{
_player2.top += 5;
_player2.bottom += 5;
}
if (_player2_map.bottom <= _player2.bottom)
{
_player2.top -= 5;
_player2.bottom -= 5;
}
// Player 2 총알 발사
if (KEYMANAGER->isOnceKeyDown('N'))
{
if (_player2_mode == 1)
bulletFire2();
if (_player2_mode == 2)
player2_mode2();
if (_player2_mode == 3)
player2_mode3();
if (_player2_mode == 4)
player2_mode4();
}
// Player 2 모드 변경
if (KEYMANAGER->isOnceKeyDown('M'))
{
_player2_mode++;
if (_player2_mode > 4)
{
_player2_mode = 1;
}
}
// Wall 움직임
if (_wall_change)
{
_wall.top -= _wall_speed;
_wall.bottom -= _wall_speed;
}
else
{
_wall.top += _wall_speed;
_wall.bottom += _wall_speed;
}
// Wall 방향 전환 시 벽 모양 랜덤 생성, 속도 랜덤 설정
if (_wall.bottom > _player2_map.bottom)
{
_wall = RectMake(WINSIZEX / 2 - 42, WINSIZEY / 2 + 250, RND->getFromIntTo(30, 85), 100);
_wall_speed = RND->getFromIntTo(5, 15);
_wall_change = true;
}
if (_wall.top < _player2_map.top)
{
_wall = RectMake(WINSIZEX / 2 + 15, WINSIZEY / 2 - 250, 30, RND->getFromIntTo(100, 400));
_wall_speed = RND->getFromIntTo(5, 15);
_wall_change = false;
}
// Wall 충돌 처리 (Player 1, 2 순)
RECT WALL_TEMP;
for (int i = 0; i < WALL_BULLMAX; i++)
{
if (IntersectRect(&WALL_TEMP, &_wall, &_player1_bullet[i].rc))
{
_player1_bullet[i].isFire = false;
}
if (IntersectRect(&WALL_TEMP, &_wall, &_player2_bullet[i].rc))
{
_player2_bullet[i].isFire = false;
}
}
// 모드에 따른 발사 조건 처리
// Player 1
if (_player1_mode >= 1)
{
bulletMove();
}
if (_player1_mode >= 2)
{
player1_mode2_Move();
}
if (_player1_mode >= 3)
{
player1_mode3_Move();
}
if (_player1_mode >= 4)
{
player1_mode4_Move();
}
// Player 2
if (_player2_mode >= 1)
{
bulletMove2();
}
if (_player2_mode >= 2)
{
player2_mode2_Move();
}
if (_player2_mode >= 3)
{
player2_mode3_Move();
}
// 패배 (P1, P2의 상태가 false 일떄)
if (_player1_state == false)
{
this->init();
}
if (_player2_state == false)
{
this->init();
}
}
else
{
if (KEYMANAGER->isOnceKeyDown(VK_RETURN))
{
_isStart = true;
}
}
}
// 출력
void playGround::render(HDC hdc)
{
HDC backDC = this->getBackBuffer()->getMemDC();
if (!_mapchange)
{
PatBlt(backDC, 0, 0, WINSIZEX, WINSIZEY, WHITENESS);
}
else
{
PatBlt(backDC, 0, 0, WINSIZEX, WINSIZEY, DSTINVERT);
}
// 위에 건들지마라
//================제발 이 사이에 좀 그립시다==========================
// Player 1 맵 출력
Rectangle(backDC, _player1_map);
// Player 2 맵 & P1 4 SK 맵 출력
Rectangle(backDC, _player2_map);
HBRUSH brush3 = CreateSolidBrush(RGB(23, 0, 255));
HBRUSH oldBrush3 = (HBRUSH)SelectObject(backDC, brush3);
Rectangle(backDC, _lockWall);
SelectObject(backDC, oldBrush3);
DeleteObject(brush3);
// Wall 출력
Rectangle(backDC, _wall);
//******************************************************************************
// 시작 안내 문구
if (_isStart == false)
{
char str1[128];
char str2[128];
char str3[128];
sprintf_s(str1, "= = = = = = = = = = = = = = = = = = = = = = = = =");
sprintf_s(str2, " 시작하려면 'Enter'를 누르세요");
sprintf_s(str3, "= = = = = = = = = = = = = = = = = = = = = = = = =");
TextOut(backDC, WINSIZEX / 2 - 150, WINSIZEY / 2 - 25, str1, strlen(str1));
TextOut(backDC, WINSIZEX / 2 - 150, WINSIZEY / 2, str2, strlen(str2));
TextOut(backDC, WINSIZEX / 2 - 150, WINSIZEY / 2 + 25, str3, strlen(str3));
}
//******************************************************************************
// Player 1 출력
Rectangle(backDC, _player);
// Player 1 총알 출력
for (int i = 0; i < PLAYER1_BULLETMAX; i++)
{
if (!_player1_bullet[i].isFire) continue;
Ellipse(backDC, _player1_bullet[i].rc);
}
// Player 1 모드 출력
char str[50];
sprintf_s(str, "%d", _player1_mode);
TextOut(backDC, _player.left, _player.top - 20, str, strlen(str));
// Player 1 게이지 출력
Rectangle(backDC, _player1_backGauge);
HBRUSH brush1 = CreateSolidBrush(RGB(_p1_r, _p1_g, 0));
HBRUSH oldBrush1 = (HBRUSH)SelectObject(backDC, brush1);
Rectangle(backDC, _player1_frontGauge);
SelectObject(backDC, oldBrush1);
DeleteObject(brush1);
// P1 4 SK 아비터 출력
Rectangle(backDC, _Arbiter);
//******************************************************************************
// Player 2 출력
Rectangle(backDC, _player2);
// Player 2 총알 출력
for (int i = 0; i < PLAYER2_BULLETMAX; i++)
{
if (!_player2_bullet[i].isFire) continue;
Ellipse(backDC, _player2_bullet[i].rc);
}
// Player 2 모드 출력
char str2[50];
sprintf_s(str2, "%d", _player2_mode);
TextOut(backDC, _player2.right, _player2.top - 20, str2, strlen(str2));
// Player 2 게이지 출력
Rectangle(backDC, _player2_backGauge);
HBRUSH brush2 = CreateSolidBrush(RGB(_p2_r, _p2_g, 0));
HBRUSH oldBrush2 = (HBRUSH)SelectObject(backDC, brush2);
Rectangle(backDC, _player2_frontGauge);
SelectObject(backDC, oldBrush2);
DeleteObject(brush2);
//******************************************************************************
// 조작법 출력
char str10[128];
char str20[128];
sprintf_s(str10, " 상하좌우 : WSAD 발사 : Z 모드 전환 : X ");
sprintf_s(str20, " 상하좌우 : UJHK 발사 : N 모드 전환 : M ");
TextOut(backDC, WINSIZEX / 2 - 425, WINSIZEY / 2 + 365, str10, strlen(str10));
TextOut(backDC, WINSIZEX / 2 + 100, WINSIZEY / 2 + 365, str20, strlen(str20));
//==================================================
//여기도 건들지마라
this->getBackBuffer()->render(hdc, 0, 0);
}
// 발사용 함수 (Player 1 - MODE 1)
void playGround::bulletFire()
{
for (int i = 0; i < PLAYER1_BULLETMAX; i++)
{
if (_player1_bullet[i].isFire) continue;
_player1_bullet[i].x = _player.right + 10;
_player1_bullet[i].y = (_player.top + _player.bottom) / 2;
_player1_bullet[i].rc = RectMakeCenter(_player1_bullet[i].x, _player1_bullet[i].y, 20, 20);
_player1_bullet[i].isFire = true;
break;
}
}
// 발사용 함수 (Player 2 - MODE 1)
void playGround::bulletFire2()
{
for (int i = 0; i < PLAYER2_BULLETMAX; i++)
{
if (_player2_bullet[i].isFire) continue;
_player2_bullet[i].x = _player2.left - 10;
_player2_bullet[i].y = (_player2.top + _player2.bottom) / 2;
_player2_bullet[i].rc = RectMakeCenter(_player2_bullet[i].x,
_player2_bullet[i].y, 20, 20);
_player2_bullet[i].isFire = true;
break;
}
}
// 발사용 함수 (Player 1 - MODE 2)
void playGround::player1_mode2()
{
for (int i = 0; i < PLAYER1_BULLETMAX; i += 5)
{
if (_player1_bullet[i].isFire) continue;
_player1_bullet[i].x = _player.right + 10;
_player1_bullet[i].y = (_player.top + _player.bottom) / 2;
_player1_bullet[i].rc = RectMakeCenter(_player1_bullet[i].x, _player1_bullet[i].y, 20, 20);
_player1_bullet[i].isFire = true;
// 210506 추가
_player1_bullet[i].num = _count;
_count++;
if (_count > 5)
{
_count = 0;
break;
}
}
}
// 출력용 함수 (Player 1 - MODE 2)
void playGround::player1_mode2_Move()
{
for (int i = 0; i < PLAYER1_BULLETMAX; i += 5)
{
if (!_player1_bullet[i].isFire) continue;
if (_player1_bullet[i].x > WINSIZEX + 50) _player1_bullet[i].isFire = false;
// 210506 추가 (순서 1번 탄환부터 ~ 5번 탄환까지)
if (_player1_bullet[i].num % 5 == 0)
{
_player1_bullet[i].x += _player1_bullet[i].speed;
_player1_bullet[i].y -= 6;
_player1_bullet[i].rc = RectMakeCenter(_player1_bullet[i].x, _player1_bullet[i].y, 20, 20);
}
if (_player1_bullet[i].num % 5 == 1)
{
_player1_bullet[i].x += _player1_bullet[i].speed;
_player1_bullet[i].y -= 3;
_player1_bullet[i].rc = RectMakeCenter(_player1_bullet[i].x, _player1_bullet[i].y, 20, 20);
}
if (_player1_bullet[i].num % 5 == 2)
{
_player1_bullet[i].x += _player1_bullet[i].speed;
_player1_bullet[i].rc = RectMakeCenter(_player1_bullet[i].x, _player1_bullet[i].y, 20, 20);
}
if (_player1_bullet[i].num % 5 == 3)
{
_player1_bullet[i].x += _player1_bullet[i].speed;
_player1_bullet[i].y += 3;
_player1_bullet[i].rc = RectMakeCenter(_player1_bullet[i].x, _player1_bullet[i].y, 20, 20);
}
if (_player1_bullet[i].num % 5 == 4)
{
_player1_bullet[i].x += _player1_bullet[i].speed;
_player1_bullet[i].y += 6;
_player1_bullet[i].rc = RectMakeCenter(_player1_bullet[i].x, _player1_bullet[i].y, 20, 20);
}
RECT temp;
if (IntersectRect(&temp, &_player2, &_player1_bullet[i].rc) && _player1_bullet[i].isFire)
{
setGauge();
_player1_bullet[i].isFire = false;
break;
}
}
}
// 발사용 함수 (Player 2 - MODE 2)
void playGround::player2_mode2()
{
for (int i = 0; i < PLAYER2_BULLETMAX; i += 5)
{
if (_player2_bullet[i].isFire) continue;
_player2_bullet[i].x = _player2.left - 10;
_player2_bullet[i].y = (_player2.top + _player2.bottom) / 2;
_player2_bullet[i].rc = RectMakeCenter(_player2_bullet[i].x, _player2_bullet[i].y, 20, 20);
_player2_bullet[i].isFire = true;
// 210506 추가
_player2_bullet[i].num = _count;
_count++;
if (_count > 5)
{
_count = 0;
break;
}
}
}
// 출력용 함수 (Player 2 - MODE 2)
void playGround::player2_mode2_Move()
{
for (int i = 0; i < PLAYER2_BULLETMAX; i++)
{
if (!_player2_bullet[i].isFire) continue;
if (_player2_bullet[i].x > WINSIZEX + 50) _player2_bullet[i].isFire = false;
// 210506 추가 (순서 1번 탄환부터 ~ 5번 탄환까지)
if (_player2_bullet[i].num % 5 == 0)
{
_player2_bullet[i].x -= _player2_bullet[i].speed;
_player2_bullet[i].y -= -6;
_player2_bullet[i].rc = RectMakeCenter(_player2_bullet[i].x, _player2_bullet[i].y, 20, 20);
}
if (_player2_bullet[i].num % 5 == 1)
{
_player2_bullet[i].x -= _player2_bullet[i].speed;
_player2_bullet[i].y -= -3;
_player2_bullet[i].rc = RectMakeCenter(_player2_bullet[i].x, _player2_bullet[i].y, 20, 20);
}
if (_player2_bullet[i].num % 5 == 2)
{
_player2_bullet[i].x -= _player2_bullet[i].speed;
_player2_bullet[i].rc = RectMakeCenter(_player2_bullet[i].x, _player2_bullet[i].y, 20, 20);
}
if (_player2_bullet[i].num % 5 == 3)
{
_player2_bullet[i].x -= _player2_bullet[i].speed;
_player2_bullet[i].y -= +3;
_player2_bullet[i].rc = RectMakeCenter(_player2_bullet[i].x, _player2_bullet[i].y, 20, 20);
}
if (_player2_bullet[i].num % 5 == 4)
{
_player2_bullet[i].x -= _player2_bullet[i].speed;
_player2_bullet[i].y -= +6;
_player2_bullet[i].rc = RectMakeCenter(_player2_bullet[i].x, _player2_bullet[i].y, 20, 20);
}
RECT temp;
if (IntersectRect(&temp, &_player, &_player2_bullet[i].rc) && _player2_bullet[i].isFire)
{
setGauge2();
_player2_bullet[i].isFire = false;
break;
}
}
}
// 발사용 함수 (Player 1 - MODE 3)
void playGround::player1_mode3()
{
for (int i = 0; i < PLAYER1_BULLETMAX; i++)
{
if (_player1_bullet[i].isFire) continue;
_player1_bullet[i].x = _player.right + 10;
_player1_bullet[i].y = (_player.top + _player.bottom) / 2;
_player1_bullet[i].rc = RectMakeCenter(_player1_bullet[i].x, _player1_bullet[i].y, 20, 20);
_player1_bullet[i].isFire = true;
break;
}
}
// 출력용 함수 (Player 1 - MODE 3)
void playGround::player1_mode3_Move()
{
for (int i = 0; i < PLAYER1_BULLETMAX; i++)
{
if (!_player1_bullet[i].isFire) continue;
if (_player1_bullet[i].x > WINSIZEX + 50) _player1_bullet[i].isFire = false;
_player1_bullet[i].x += _player1_bullet[i].speed;
_player1_bullet[i].rc = RectMakeCenter(_player1_bullet[i].x, _player1_bullet[i].y, 20, 20);
if (_player1_bullet[i].rc.right > _player1_map.right)
{
// 1P가 바닥쪽에서 쏘는 동안 2P가 위에 있을 때
if (_player1_bullet[i].rc.top > _player2.top)
{
_player1_bullet[i].y -= 7.5;
_player1_bullet[i].rc = RectMakeCenter(_player1_bullet[i].x, _player1_bullet[i].y, 20, 20);
}
// 1P가 위쪽에서 쏘는 동안 2P가 아래에 있을 때
if (_player1_bullet[i].rc.bottom < _player2.bottom)
{
_player1_bullet[i].y += 7.5;
_player1_bullet[i].rc = RectMakeCenter(_player1_bullet[i].x, _player1_bullet[i].y, 20, 20);
}
}
RECT temp;
if (IntersectRect(&temp, &_player2, &_player1_bullet[i].rc) && _player1_bullet[i].isFire)
{
setGauge();
_player1_bullet[i].isFire = false;
break;
}
}
}
// 발사용 함수 (Player 2 - MODE 3)
void playGround::player2_mode3()
{
for (int i = 0; i < PLAYER2_BULLETMAX; i++)
{
if (_player2_bullet[i].isFire) continue;
_player2_bullet[i].x = _player2.left - 10;
_player2_bullet[i].y = (_player2.top + _player2.bottom) / 2;
_player2_bullet[i].rc = RectMakeCenter(_player2_bullet[i].x,
_player2_bullet[i].y, 20, 20);
_player2_bullet[i].isFire = true;
break;
}
}
// 출력용 함수 (Player 2 - MODE 3)
void playGround::player2_mode3_Move()
{
for (int i = 0; i < PLAYER2_BULLETMAX; i++)
{
if (!_player2_bullet[i].isFire) continue;
if (_player2_bullet[i].x > WINSIZEX + 50) _player2_bullet[i].isFire = false;
_player2_bullet[i].x -= _player2_bullet[i].speed;
_player2_bullet[i].rc = RectMakeCenter(_player2_bullet[i].x, _player2_bullet[i].y, 20, 20);
if (_player2_bullet[i].rc.left < _player2_map.left)
{
//2 P가 바닥쪽에서 쏘는 동안 1P가 위에 있을 때
if (_player2_bullet[i].rc.top > _player.top)
{
_player2_bullet[i].y -= 7.5;
_player2_bullet[i].rc = RectMakeCenter(_player2_bullet[i].x, _player2_bullet[i].y, 20, 20);
}
// 2P가 위쪽에서 쏘는 동안 1P가 아래에 있을 때
if (_player2_bullet[i].rc.bottom < _player.bottom)
{
_player2_bullet[i].y += 7.5;
_player2_bullet[i].rc = RectMakeCenter(_player2_bullet[i].x, _player2_bullet[i].y, 20, 20);
}
}
RECT temp;
if (IntersectRect(&temp, &_player, &_player2_bullet[i].rc) && _player2_bullet[i].isFire)
{
setGauge2();
_player2_bullet[i].isFire = false;
break;
}
}
}
// 발사용 함수 (Player 1 - MODE 4)
void playGround::player1_mode4()
{
if (!_use4skile)
{
_use4skile = true;
_Arbiter = RectMakeCenter(0, WINSIZEY / 2 - 360, 70, 50);
}
else
{
}
}
// 출력용 함수 (Player 1 - MODE 4)
void playGround::player1_mode4_Move()
{
_Arbiter.left += 5;
_Arbiter.right += 5;
if (_Arbiter.left >= (_player2_map.left + _player2_map.right) / 2)
{
_Arbiter = RectMakeCenter(800, WINSIZEY / 2 - 360, 70, 50);
_lockWall = RectMake(_player2.left - 15, _player2.top - 15, 130, 80);
_lockKey = true;
}
}
// P2 4 SK 함수
void playGround::player2_mode4()
{
_player1_map = RectMake( (WINSIZEX / 2 - 450) + 100, (WINSIZEY / 2 - 100), 400 / 2, 600 / 2);
_reverseKey = true;
}
// 총알 움직임용 (Player 1)
void playGround::bulletMove()
{
for (int i = 0; i < PLAYER1_BULLETMAX; i++)
{
if (!_player1_bullet[i].isFire) continue;
if (_player1_bullet[i].x > WINSIZEX + 50) _player1_bullet[i].isFire = false;
_player1_bullet[i].x += _player1_bullet[i].speed;
_player1_bullet[i].rc = RectMakeCenter(_player1_bullet[i].x, _player1_bullet[i].y , 20, 20);
RECT temp;
if (IntersectRect(&temp, &_player2, &_player1_bullet[i].rc) && _player1_bullet[i].isFire)
{
setGauge();
_player1_bullet[i].isFire = false;
break;
}
}
}
// 총알 움직임용 (Player 2)
void playGround::bulletMove2()
{
for (int i = 0; i < PLAYER2_BULLETMAX; i++)
{
if (!_player2_bullet[i].isFire) continue;
if (_player2_bullet[i].x > WINSIZEX + 50) _player2_bullet[i].isFire = false;
_player2_bullet[i].x -= _player2_bullet[i].speed;
_player2_bullet[i].rc = RectMakeCenter(_player2_bullet[i].x,
_player2_bullet[i].y, 20, 20);
RECT temp;
if (IntersectRect(&temp, &_player, &_player2_bullet[i].rc) && _player2_bullet[i].isFire)
{
setGauge2();
_player2_bullet[i].isFire = false;
break;
}
}
}
// 총알 맞은 경우 변하는 게이지 (Player 2)
void playGround::setGauge()
{
_player2_frontGauge.left += 10;
if (_player2_frontGauge.left >= _player2_backGauge.right)
{
_player2_state = false;
_player2_frontGauge.left = _player2_backGauge.right;
}
if (_player2_frontGauge.right - _player2_frontGauge.left < 275)
{
_p2_r = 255;
_p2_g = 255;
}
if (_player2_frontGauge.right - _player2_frontGauge.left < 100)
{
_p2_r = 255;
_p2_g = 0;
}
}
// 총알 맞은 경우 변하는 게이지 (Player 1)
void playGround::setGauge2()
{
_player1_frontGauge.right -= 10;
if (_player1_frontGauge.left >= _player1_frontGauge.right)
{
_player1_state = false;
_mapchange = true;
_player1_frontGauge.left = _player1_frontGauge.right;
}
if (_player1_frontGauge.right - _player1_frontGauge.left < 275)
{
_p1_r = 255;
_p1_g = 255;
}
if (_player1_frontGauge.right - _player1_frontGauge.left < 100)
{
_mapchange = true;
_p1_r = 255;
_p1_g = 0;
}
}
어떻게 구현해야 할까?
- .1/2 player의 움직임, 발사, 총알 모드 변경, 체력게이지, 맵을 구현하자
- 총알 모드 변경을 구현하고, 미사일이 어떻게 나갈지 생각해보자
- player가 각각의 맵 밖으로 나가지 못하게 구현하자
- 중간 벽을 구현하자
- 궁극기는 무엇으로 할까?
로직은?
1. 각각의 움직임은 키 매니저를 이용하여 움직임을 설정해준다.
발사는 슈팅 베이직!에 있는 자료를 활용한다.
총알 모드 변경은 간단하게 int형 변수를 선언하여 변경한다
체력 게이지는 슈팅 베이직!에 있는 자료를 활용한다.
맵과 맵 바깥으로의 이동 금지 설정은 API 사각형 수업날 내부 사각형 움직이는걸 생각해보자.
2. 중간 벽은 간단하게 RECT를 생성해서 만들자
일정 좌표를 도착할 때 BOOL 값을 이용해서 위아래로 왔다 갔다 하게 하자
벽이 일정한 속도, 같은 모양을 하면 재미 없기 떄문에 속도와 모양을 랜덤으로 설정하자.
3. 기본 미사일 발사, 움직임은 슈팅 베이직!을 활용한다.
샷건의 발사는 슈팅 베이직을 활용하지만, 움직임은 어떻게 구현할지 생각해보자.
유도탄은 미사일이 맵 밖을 나갔을 때의 두 플레이어간의 탑 바텀을 크기를 비교해 일정 속도를 주어 휘어지는 것 처럼 보여지게 한다.
1P의 궁극기는 스타크래프트의 아비터를 활용하여 P2를 얼려버린다.
2P의 궁극기는 맵 절반 감소 및 움직임 키 리버스를 시킨다.
결과화면
1P 2P 움직임, 플레이어 위에 현재 단계 표시, 조작방법 표기,
1단계 모드 발사 장면, 중간 벽 이동(속도&크기 랜덤)
1P 2P 움직임이 맵 내부안에서만 움직이는 모습
1P 2P 모드 전환 및 2단계 모드(샷건) 발사장면, 체력 게이지 감소
1P 2P 3단계 모드(유도탄) 발사장면, 체력 게이지 감소
1P 2P 4단계 모드(궁극기) 발사장면
1P의 궁극기는 스타크래프트 아비터 스테이스 필드를 접목한 움직임 봉인
2P의 궁극기는 방향키 전환 및, 맵 절반감소
체력게이지 색상 전환, 게임 종료
개인적으로 해보고 싶은 심화학습
1. 현재는 초록게이지 상태에서도 불구하고 궁극기가 구현되지만 조금 더 심화적으로 하면 플레이어의 체력이 빨간색이 되었을 떄 궁극기가 구현되게 하고 싶었다.
2. 종료 될 시 1P 혹은 2P가 승리했다는 승리 안내 문구도 없고, 바로 재 시작하는 부분이 많이 아쉽다. 조금더 시간이 있었으면 이부분을 보완하고 싶다.
아쉬운점
궁극기로 여러 아이디어가 있었지만 시간도 부족하고, 내 개인적인 역량이 부족해 해보지 못한 아이디어들이 많다. 🤦♂️
궁극기.
화면 뒤집기, 블랙홀을 구현해 중력값을 이용하여 캐릭터 빨려들어가게 하기,
움직임이 영원히 고정되는 것이 아닌 N초 고정시키기, 캐릭터 간 체력 변경하기 등
아이디어는 있었지만 화면을 뒤집는 방법은 잘 몰라서 포기했다.
블랙홀도 원으로 구현하기엔 쉽지 않았고, 중력값을 이용해 캐릭터를 빨려들어가게 하는 부분이 나에겐 어렵게 느껴졌다.
움직임을 N초간 고정하는 기술은 몇 초 지난것을 인식하여 구현하면 될 것 같았지만 차마 알아볼 시간이 없어 해보지 못했다.
캐릭터 간 체력 변경하기는 너무한 것 같아 구현하지 않았다. 않은게 아니라 못한거겠지만 😜
화면.
조금 더 리얼한 미사일 게임을 제작하기 위해 배경화면을 넣어보고 싶었지만 소스코드의 어디 부분을 어떻게 수정해야 될지 몰라 넣어보지 못한게 아쉽다.
마치며
그래도 2인용 미사일 게임을 제작하면서 내가 제작하는 것들이 눈에 명확하게 보이고, 버그 없이제대로 적용되는 모습이 너무나도 좋았다.
개인적인 내 생각이지만 '개발이 재밌다!' 라고 생각될 만큼 정말 좋은 경험이였다. 역시 어떤 일을 하던간에 흥미를 느껴야지만 잘 되는 것 같다. 💕
'학원 > 경일게임아카데미' 카테고리의 다른 글
32. 스무번째 수업 (0) | 2023.01.10 |
---|---|
31. 열아홉번째 수업 (0) | 2023.01.09 |
29. 열여덟번째 수업 (2) | 2023.01.06 |
28. 열일곱번째 수업 (0) | 2022.12.29 |
27. 열여섯번째 수업과제 [악어 게임] (0) | 2022.12.29 |