WIN32API FrameWork/한단계씩 직접 구현

30. 스킬 구현 2 - 아우렐리온 솔 W

hyrule 2022. 5. 23. 22:18

http://hyrule.tistory.com/111 

 

*** 공부 방법 ***

1. 코딩을 해야 하는 부분은 첫 부분에 변수나 함수, 메소드에 대한 선언이 코드블럭으로 표시되어 있다. //ex) MakeFunction(); 2. 코드블럭 하단에는 해당 선언에 대한 구현 로직이 작성되어 있다. 처

hyrule.tistory.com

 


- 이번에도 이미지로 설명이 더 빠를 것 같아 이미지로 설명을 대신한다.

출처: https://tenor.com/view/aurelion-sol-gif-20409531

- 해당 내용을 구현해보자.

 

< 로직 > 

- 초기화할 때 주인 포인터를 등록하고, 해당 주인 포인터를 따라다녀야 한다.

- 별들은 모두 거리를 동일하게 유지한 채 회전한다.

- (연습을 위해)Shift + 2 키를 누르면 아우렐리온 솔의 w를 누른 것과 동일한 효과를 발동시킨다.

 

- 그냥 원을 그려주는 클래스를 CPlayer에서 3개 동적 할당하여 돌리는 방법도 있고,

아예 해당 기능을 담당하는 클래스를 만들어 원하는 게임오브젝트에 붙여주는 방법도 있고

다양한 방법으로 구현 가능하다.

-- 어떻게 하든 똑같은 모습이 나오도록 구현해보자.

더보기
//SolBullet.h

#pragma once
#include "GameObject.h"
class CSolBullet :
    public CGameObject
{
    friend class CScene;

private:

    //회전 반경
    float m_RotatingRadius;

    //회전 속도
    float   m_RotatingAngleSpeed;

    //각도 저장
    float   m_RotatingAngle;

    //주위를 회전할 총알의 갯수와 그에 따른 각도
    int     m_SolBulletNum;
    float   m_SolBulletNumAngle;
    //실제 표시되는 총알의 중심점 m_BulletNum개
    std::vector<Vector2> m_SolBulletCenter;


    //스킬 관련 변수들

    //시전 중인지 여부
    bool    m_isCasting;

    //시전 방향(현재 확장 중인지 다시 원래로 돌아가는 중인지)
    float   m_SolSkillDir;

    //스킬의 지속 시간
    float   m_SkillDuration;

    //남아있는 지속 시간
    float   m_SkillDurationLeft;

    //회전 속도 최솟값(기본값)
    float   m_RotatingAngleSpeedMin;

    //회전 속도 최댓값
    float   m_RotatingAngleSpeedMax;

    //회전 반경 최솟값
    float   m_RotatingRadiusMin;

    //회전 반경 최댓값
    float   m_RotatingRadiusMax;

    //확대 속도
    float   m_ExpandSpeed;
    



protected:
    CSolBullet();
    CSolBullet(const CSolBullet& Obj);
    virtual ~CSolBullet();

public:
    bool Init(CGameObject* Obj);
    void Update(float DeltaTime);
    void Render(HDC hDC, float DeltaTime);

    void SetSolBulletNumAngle(int Num);

    //실제 스킬 로직 메소드
    bool SkillLogic(float DeltaTime);

    //이 클래스를 달고있는 클래스에서 스킬을 사용할 때 호출하는 메소드
    void EnableSkill()
    {
        m_isCasting = true;
    }
};

 

//SolBullet.cpp

#include "SolBullet.h"

CSolBullet::CSolBullet()
{
}

CSolBullet::CSolBullet(const CSolBullet& Obj) :
	CGameObject(Obj),
	m_isCasting(Obj.m_isCasting),
	m_SolSkillDir(Obj.m_SolSkillDir),
	m_SkillDuration(Obj.m_SkillDuration),
	m_SkillDurationLeft(Obj.m_SkillDurationLeft),
	m_RotatingAngleSpeedMin(Obj.m_RotatingAngleSpeedMin),
	m_RotatingAngleSpeedMax(Obj.m_RotatingAngleSpeedMax),
	m_RotatingRadiusMin(Obj.m_RotatingRadiusMin),
	m_RotatingRadiusMax(Obj.m_RotatingRadiusMax),
	m_ExpandSpeed(Obj.m_ExpandSpeed)
{
}

CSolBullet::~CSolBullet()
{
}

bool CSolBullet::Init(CGameObject* Obj)
{
	CGameObject::Init(Obj);

	//무조건 주인 오브젝트가 있어야 하므로 혹시나 등록되지 않았으면 false 반환해서 삭제
	if (!m_MasterObject)
		return false;

	m_RotatingRadius = 100.f;
	m_RotatingAngleSpeed = 180.f;
	m_RotatingAngle = 0.f;


	m_isCasting = false;
	//2초에 걸쳐서 넓어졌다가 2초에 걸쳐서 돌아온다.
	m_RotatingRadiusMin = 100.f;
	m_RotatingRadiusMax = 200.f;
	m_RotatingAngleSpeedMin = 200.f;
	m_RotatingAngleSpeedMax = 400.f;
	
	m_SkillDuration = 5.f;
	m_SkillDurationLeft = 5.f;
	m_ExpandSpeed = 50.f;

	//일단 주위를 회전할 총알 기본 3개로 설정
	SetSolBulletNumAngle(3);

	SetSize(50.f, 50.f);
	SetPivot(0.5f, 0.5f);


	return true;
}

void CSolBullet::Update(float DeltaTime)
{
	this->CGameObject::Update(DeltaTime);


	//주인 오브젝트를 따라다닌다.
	m_Pos = m_MasterObject->GetPos();

	//매 프레임 총알의 회전량을 구한다.
	m_RotatingAngle += m_RotatingAngleSpeed * DeltaTime;

	//각도가 360도를 넘어가면, 360도를 뺴줘서 숫자가 너무 커지지 않도록 해준다.
	if (m_RotatingAngle >= 360.f)
		m_RotatingAngle -= 360.f;

	size_t size = m_SolBulletCenter.size();
	for (size_t i = 0; i < size; ++i)
	{
		//라디안값을 구한다.
		float RotAngleRad = DegreeToRadian(m_RotatingAngle + (i * m_SolBulletNumAngle));

		//라디안값을 통해 토네이도 총알의 중심점을 구해낸다.
		m_SolBulletCenter[i].x = m_Pos.x + (cosf(RotAngleRad) * m_RotatingRadius);
		m_SolBulletCenter[i].y = m_Pos.y + (sinf(RotAngleRad) * m_RotatingRadius);

	}


	//스킬 사용 처리
	if (m_isCasting)
	{
		m_SkillDurationLeft -= DeltaTime;

		//SkillLogic이 작동을 마치고 True를 반환하면 
		if (SkillLogic(DeltaTime))
		{
			m_isCasting = false;
			m_SkillDurationLeft = m_SkillDuration;
		}
	}

}

void CSolBullet::Render(HDC hDC, float DeltaTime)
{
	CGameObject::Render(hDC, DeltaTime);

	size_t size = m_SolBulletCenter.size();
	for (size_t i = 0; i < size; ++i)
	{
		//구한 토네이도 총알의 중심점으로부터 총알을 그려낸다.
		Vector2 RenderLeftTop = m_SolBulletCenter[i] - (m_Size * m_Pivot);

		Ellipse(hDC, (int)RenderLeftTop.x,
			(int)RenderLeftTop.y,
			(int)(RenderLeftTop.x + m_Size.x),
			(int)(RenderLeftTop.y + m_Size.y));

	}

}

void CSolBullet::SetSolBulletNumAngle(int Num)
{
	m_SolBulletNum = Num;
	m_SolBulletNumAngle = 360.f / Num;
	m_SolBulletCenter.resize(Num);
}


bool CSolBullet::SkillLogic(float DeltaTime)
{

	//아직 시전시간이 남아있으면 증가
	if (m_SkillDurationLeft >= 0.f)
		m_SolSkillDir = 1.f;

	//시전시간이 끝났으면 감소
	else
		m_SolSkillDir = -1.f;

	//위의 값에 따라 증가 혹은 감소
	m_RotatingAngleSpeed += m_SolSkillDir * m_ExpandSpeed * DeltaTime * 2.f;
	m_RotatingRadius += m_SolSkillDir * m_ExpandSpeed * DeltaTime;

	//반경이 최대값을 넘어가면 최대값으로 고정(반경, 속도 둘다)
	if (m_RotatingRadius >= m_RotatingRadiusMax)
	{
		m_RotatingRadius = m_RotatingRadiusMax;
		m_RotatingAngleSpeed = m_RotatingAngleSpeedMax;
	}
	//반대로 반경이 최솟값(기본값)이하로 떨어지면 최솟값으로 고정
	else if (m_RotatingRadius <= m_RotatingRadiusMin)
	{
		m_RotatingRadius = m_RotatingRadiusMin;
		m_RotatingAngleSpeed = m_RotatingAngleSpeedMin;

		//여기에 들어왔다는 것은 시전이 끝났다는 얘기이므로 스킬을 다시 사용가능하게 변경한다.
		m_isCasting = false;
		m_SkillDurationLeft = m_SkillDuration;


		//true 반환 = 스킬 시전 종료
		return true;
	}


	//false 반환 = 스킬 시전 중
	return false;
}

 

* 아우렐리온 솔의 스킬 작동 방식은 기존의 스킬들과 약간 다르다.

- 다른 스킬들은 스킬을 시전할 떄 객체가 생성되는 방식이었지만, 

이 스킬은 스킬을 시전하면 생성되어있는 객체가 변화하는 방식이기 떄문이다.

- 이 스킬은 스킬 작동 메소드를 따로 만들어서 호출하는 방식으로 구현해주어야 한다.

- 입력 메소드 등록 및 스킬 초기화 과정은 여러번 작성했으므로 생략한다.

//Player.cpp

void CPlayer::AurelionSol()
{
	//쿨타임이면 그냥 return
	if (m_SkillCoolTimeSet[(int)EPlayerSkill::AurelionSol].isCoolTime)
		return;

	EnterSkillCoolTIme((int)EPlayerSkill::AurelionSol);

	//m_Slave 목록에서 찾아도 되지만 최적화를 위해 포인터 변수에 저장해 놓고 호출하였다.
	m_Sol->EnableSkill();
		
}

< 결과 >

GameFrameworkStepbyStep_30_TornadoBullet.zip
0.05MB