본문으로 바로가기

 

2020_0601_Framework.zip
0.03MB


 

[프로그램 설계]

1. Enemy 오브젝트를 선형모드로 변환하고, 게임 영역의 4방에 배치

2. 배치 완료된 오브젝트는 랜덤 프레임동안 대기하며 플레이어 방향쪽으로 방향 조준

3. 대기가 끝나면 해당 순간의 플레이어 방향으로 발사

4. 발사된 Enemy는 랜덤으로 설정되는 speed 값과 발사 순간의 방향 vector를 계산하여 이동 처리

5. Enemy 오브젝트가 게임 영역의 4개 모서리에 도달시 Enemy Object와 충돌 처리하고, Reset

6. Enemy 오브젝트가 플레이어와 충돌시 오브젝트 색상에 따라 결과 처리 후, Reset

 

[구현 중점]

1. Line to Line 충돌

  - Enemy(Line) <-> 게임 영역(Line)

2. Line to Rect 충돌

  - Enemy(Line) <-> 플레이어(Rect)

  => Rect를 4개의 Line으로 분할하여 각 Line을 모두 체크

3. Normalized Vector 를 이용한 플레이어 위치 추적, 오브젝트 이동

 

[보완점]

1. Normalize 함수에서 vector의 y값이 0일 때 오작동 하는 부분 원인 찾기

2. 오브젝트 이동에 선형보간법(Linear Interpolation) 적용

 

Circle & Rect 충돌처리 프로젝트에서 수정하여 작성함

 

추가된 코드

Line class
더보기
public:
	void operator+=(const Vector2& v) // 연산자 오버로딩(Enemy->Fall()에서 사용)
	{
		begin = begin + v;
		end = end + v;
	}

 

Player
더보기
// 멤버 변수
public:
	Line lines[4];		// Rect의 네 변을 Line변수로 할당(선-선 충돌처리에서 사용)
    
// 멤버 함수
public:
	void SetLines();	// lines 배열 초기화 함수
///////////////////////////////////////////////////////////////////////////////////////////////
void Player::SetLines() // Move() 함수안에 추가하여 움직일 때마다 Line 좌표 갱신
{
	lines[0] = {
    Vector2{(double)Right(), (double)Top()},
    Vector2{(double)Right(), (double)Bottom()}	};
    
	lines[1] = {
    Vector2{(double)Right(), (double)Bottom()},
    Vector2{(double)Left(), (double)Bottom()}	};
    
	lines[2] = {
    Vector2{(double)Left(), (double)Bottom()},
    Vector2{(double)Left(), (double)Top()}		};
    
	lines[3] = {
    Vector2{(double)Left(), (double)Top()},
    Vector2{(double)Right(), (double)Top()}		};
}

 

Enemy
더보기
enum class SHAPE_MODE // Line모드 추가
{
	NONE,
	RECT,
	ELLIPSE,
	LINE
};
// 추가한 멤버 변수
public:
	Player* pPlayer;	// 플레이어를 추적하기 위한 포인터(씬에서 객체 생성시 할당)
	Vector2 dir;		// 플레이어쪽으로 향하는 방향 벡터
	Point lineEnd;		// Line형태를 그리기 위한 끝점(pos와 dir를 조합하여 생성)
	Line line;		// Pos값과 lineEnd를 이용하여 Line변수를 만들고 Render, Collision에서 사용

// 수정한 멤버 함수
public:
	void FallDown();	// 플레이어쪽으로 향하도록 수정
	void CountToActive();	// 발사하기 전 플레이어 위치로 방향 갱신

// 추가한 멤버 함수1(Get, Set)
public:
	Point LineEnd() { return lineEnd; }
	Line Line() { return line; }
	void SetDir(const Vector2& v) { dir = v.Normal(); }

// 추가한 멤버 함수2
public:
	void SetDirToPos(Point pos);
//////////////////////////////////////////////////////////////////////////////////////////////
void Enemy::FallDown()
{
	line += (dir * speed); // Line class에서 += 연산자 오버로딩
}

void Enemy::CountToActive()
{
	--delay;
	SetDirToPos(pPlayer->GetPos()); // 발사전 딜레이 프레임 동안 플레이어 조준
	if (delay == 0)
	{
		Speed(rand() % 2 + 1.0);
		isActive = true;
	}
}

void Enemy::Render()
{
	switch (mode)
	{
		case Enemy::SHAPE_MODE::LINE:
		line.Render(hdc);	// Line class 활용하여 Render 처리
		break;
	}
}

void Enemy::SetDirToPos(Point pos)
{
	Vector2 v{ pos.x - m_tPos.x, pos.y - m_tPos.y };
	v.Normalize();
	dir = v;
	lineEnd.x = m_tPos.x + dir.x * size.x;
	lineEnd.y = m_tPos.y + dir.y * size.y;

	line = { Vector2{m_tPos.x, m_tPos.y}, Vector2{lineEnd.x, lineEnd.y} };
}

 

CollisionScene
더보기
// 게임 플레이 영역의 각 점, 선 캐싱
public:
	Vector2 rt;
	Vector2 rb;
	Vector2 lb;
	Vector2 lt;
	Line gameAreaLineRight;
	Line gameAreaLineBottom;
	Line gameAreaLineLeft;
	Line gameAreaLineTop;
/////////////////////////////////////////////////////////////////////////////////////////////
bool CollisionScene::Init()
{
	// 게임 플레이 영역 설정
	LONG center_x = (LONG)(bufferRT.right * 0.5);
	LONG center_y = (LONG)(bufferRT.bottom * 0.5);
	rect_PlayArea = { center_x - 600, center_y - 400, center_x + 600, center_y + 400 };
	rt = { (double)rect_PlayArea.right,(double)rect_PlayArea.top };
	rb = { (double)rect_PlayArea.right,(double)rect_PlayArea.bottom };
	lb = { (double)rect_PlayArea.left, (double)rect_PlayArea.bottom };
	lt = { (double)rect_PlayArea.left, (double)rect_PlayArea.top };
	gameAreaLineRight = { rt, rb };
	gameAreaLineBottom = { rb, lb };
	gameAreaLineLeft = { lb, lt };
	gameAreaLineTop = { lt, rt };

	// Enemy 생성 및 오브젝트 풀 가시화
	enemyCount = 80;
	double x{}, y{};
	double width = (double)rect_PlayArea.right - rect_PlayArea.left;
	double x_gap = width / (enemyCount * 0.25);
	double height = (double)rect_PlayArea.bottom - rect_PlayArea.top;
	double y_gap = height / (enemyCount * 0.25);
	for (int i = 0; i < enemyCount; i++)
	{
		Enemy* enemy = new Enemy;
        // 게임영역 4개 모서리 부분에 자리 잡기
		if (i < (int)(enemyCount * 0.25))
		{ // Top Line
			x = (i % (int)(enemyCount * 0.25)) * x_gap + rect_PlayArea.left + enemy->Size().x;
			y = rect_PlayArea.top + enemy->Size().x;
			enemy->Color(1);
		}
		else if (i < (int)(enemyCount * 0.5))
		{ // Right Line
			x = rect_PlayArea.right - enemy->Size().x;
			y = (i % (int)(enemyCount * 0.25)) * y_gap + rect_PlayArea.top + enemy->Size().x;
			enemy->Color(2);
		}
		else if (i < (int)(enemyCount * 0.75))
		{ // Bottom Line
			x = (i % (int)(enemyCount * 0.25)) * x_gap + rect_PlayArea.left + enemy->Size().x;
			y = rect_PlayArea.bottom - enemy->Size().x;
			enemy->Color(3);
		}
		else if (i < enemyCount)
		{ // Left Line
			x = rect_PlayArea.left + enemy->Size().x;
			y = (i % (int)(enemyCount * 0.25)) * y_gap + rect_PlayArea.top + enemy->Size().x;
			enemy->Color(4);
		}
        
		Point pos{ x, y };			// 계산된 x, y 값으로 Point 생성
		enemy->startPos = pos;		// 최초 생성 위치 저장
		enemy->pPlayer = m_pPlayer;	// 플레이어 추적을 위해 모든 Enemy 객체에 Player 포인터 할당
		enemy->SetPos(pos);			// Enemy 객체 위치 이동
		enemy->SetDirToPos(m_pPlayer->GetPos());	// Player쪽을 바라보도록 Enemy방향 설정
}

bool CollisionScene::CollideToWall(Enemy* enemy)
{ // 발사된 Enemy(Line)가 게임영역 테두리(Line)에 충돌하는 부분 처리(Line <-> Line)
	Line enemyLine = enemy->line;
	if (
		(enemyLine.IsBetween(&gameAreaLineRight) && gameAreaLineRight.IsBetween(&enemyLine))
		|| (enemyLine.IsBetween(&gameAreaLineBottom) && gameAreaLineBottom.IsBetween(&enemyLine))
		|| (enemyLine.IsBetween(&gameAreaLineLeft) && gameAreaLineLeft.IsBetween(&enemyLine))
		|| (enemyLine.IsBetween(&gameAreaLineTop) && gameAreaLineTop.IsBetween(&enemyLine))
		)
		return true;

	return false;
}

bool CollisionScene::CollisionLineRect(Enemy* pLine, Player* pRect)
{ // Enemy(Line Mode)와 Player(Rect Mode)의 충돌처리(Line <-> Rect)
/*
1. Player는 Move 호출시 마다 Rect영역의 Line값을 갱신한다
2. enemy 또한 FallDown(Move와 대응) 호출시 마다 Line값을 지속 갱신한다
3. 모든 Line이 갱신된 값을 가지고 있으므로 Player의 각 Line들을 Enemy Line과 검사하여 충돌을 확인한다
*/
	Line enemyLine = pLine->line;
	Line playAreaLine{};

	for (int i = 0; i < 4; i++)
	{
		playAreaLine = pRect->lines[i];
		if (enemyLine.IsBetween(&playAreaLine) && playAreaLine.IsBetween(&enemyLine))
			return true;
	}

	return false;
}