[D3D] Button

vector·2025년 12월 9일

Button

직교투영 카메라를 사용해서 버튼만들기

Button

  • Picking함수, Create함수, 콜백함수 생성
  • ComponentType::Button으로 만들고, GameObject에도 GetButton() 추가
  • 콜백함수(언리얼에서는 델리게이트 형식)를 만들때 람다형식의 Function을 사용하게 될 경우 포인터를 사용하게 되는데, 람다를 빠져나올때 사라진 주소값을 참조하기에 문제가 발생할 수 있다.
  • 만약 그렇다고 스마트포인터를 사용하게 되면 참조가 계속 되어, 릴리즈가 안되는 문제가 발생할 수 있다.

Button.h

#pragma once
#include "Component.h"
class Button : public Component
{
	using Super = Component;

public:
	Button();
	virtual ~Button();

	bool Picked(POINT screenPos);

	void Create(Vec2 screenPos, Vec2 size, shared_ptr<class Material> material);

	void AddOnClinckedEvent(std::function<void(void)> func);
	void InvokeOnClicked();

private:
	std::function<void(void)> _onClicked;
	RECT _rect;
};

Button.cpp

#include "pch.h"
#include "Button.h"
#include "Material.h"
#include "MeshRenderer.h"

Button::Button() : Component(ComponentType::Button) {}
Button::~Button() {}
bool Button::Picked(POINT screenPos)
{
	return ::PtInRect(&_rect, screenPos);
}

void Button::Create(Vec2 screenPos, Vec2 size, shared_ptr<class Material> material)
{
	auto gameObject = _gameObject.lock();

	float height = GRAPHICS->GetViewport().GetHeight();
	float width = GRAPHICS->GetViewport().GetWidth();

	float x = screenPos.x - width / 2;
	float y = height / 2 - screenPos.y;

	Vec3 position = Vec3(x, y, 0);

	gameObject->GetOrAddTransform()->SetPosition(position);
	gameObject->GetOrAddTransform()->SetScale(Vec3(size.x, size.y, 1));

	gameObject->SetLayerIndex(Layer_UI);

	if (gameObject->GetMeshRenderer() == nullptr)
		gameObject->AddComponent(make_shared<MeshRenderer>());


	gameObject->GetMeshRenderer()->SetMaterial(material);

	auto mesh = RESOURCES->Get<Mesh>(L"Quad");
	gameObject->GetMeshRenderer()->SetMesh(mesh);
	gameObject->GetMeshRenderer()->SetPass(0);

	// Picking
	_rect.left   = screenPos.x - size.x / 2;
	_rect.right  = screenPos.x + size.x / 2;
	_rect.top    = screenPos.y - size.y / 2;
	_rect.bottom = screenPos.y + size.y / 2;
}

void Button::AddOnClinckedEvent(std::function<void(void)> func)
{
	_onClicked = func;
}

void Button::InvokeOnClicked()
{
	if (_onClicked)
		_onClicked();
}

Scene

  • UI 피킹하는 함수 추가

Scene.cpp

void Scene::PickUI()
{
	if (INPUT->GetButtonDown(KEY_TYPE::LBUTTON) == false)
		return;

	if (GetUICamera() == nullptr)
		return;

	POINT screenPt = INPUT->GetMousePos();

	shared_ptr<Camera> camera = GetUICamera()->GetCamera();

	const auto gameObjects = GetObjects();

	for (auto& gameObject : gameObjects)
	{
		if (gameObject->GetButton() == nullptr)
			continue;

		if (gameObject->GetButton()->Picked(screenPt))
			gameObject->GetButton()->InvokeOnClicked();
	}
}

메인함수(Demo)

  • 주석으로 처리 한 부분을 Create()로 대체
  • AddOnClickedEvent()를 통해 object를 제거하는 람다함수를 Button()의 onClicked함수에 넣어서 실행시키는 방식
	// Mesh 버튼 형식
	{
		auto obj = make_shared<GameObject>();
		obj->AddComponent(make_shared<Button>());
		obj->GetButton()->Create(Vec2(100, 100), Vec2(100, 100), RESOURCES->Get<Material>(L"Veigar"));

		//obj->GetOrAddTransform()->SetLocalPosition(Vec3(0.f, 200.f, 0.f));
		//obj->GetOrAddTransform()->SetScale(Vec3(200.f));
		//obj->AddComponent(make_shared<MeshRenderer>());
		//
		//obj->SetLayerIndex(Layer_UI);
		//{
		//	obj->GetMeshRenderer()->SetMaterial(RESOURCES->Get<Material>(L"Veigar"));
		//}
		//{
		//	auto mesh = RESOURCES->Get<Mesh>(L"Quad");
		//	obj->GetMeshRenderer()->SetMesh(mesh);
		//	obj->GetMeshRenderer()->SetPass(0);
		//}

		obj->GetButton()->AddOnClickedEvent([obj]() { CUR_SCENE->Remove(obj); });

		CUR_SCENE->Add(obj);
	}

결과

참고 강의

https://www.inflearn.com/courses/lecture?courseId=329791&tab=curriculum&type=LECTURE&unitId=161179&subtitleLanguage=ko

profile
게임 클라이언트 프로그래머 준비중 (공부 및 기록용)

0개의 댓글