I'm currently making a 2D video game using the SFML library on Visual Studio 2019 community with the help of a Youtube tutorial series by Suraj Sharma:
https://www.youtube.com/watch?v=IdKZpv6xqdw&list=PL6xSOsbVA1ebkU66okpi-KViAO8_9DJKg&index=1
Recently i'm making a drop list of buttons to be implemented in the game menu's settings(Video 44 to 48)
For example,when i click on the menu's 'Settings' button the menu will switch into a 'Settings' state that comprises a drop list of resolution options for me to choose from.
Here's the code:
Gui.h
<pre>#pragma once
#ifndef GUI_H
#define GUI_H
#include "pch.h"
enum BStates { IDLE = 0,HOVER,ACTIVE };
namespace gui {
class Button
{
private:
short unsigned bStates;
short unsigned Id;
sf::RectangleShape Shape;
sf::Font* Font;
sf::Text Text;
sf::Color TextIdl;
sf::Color TextHover;
sf::Color TextActive;
sf::Color Idle;
sf::Color Hover;
sf::Color Active;
sf::Color OutlIdle;
sf::Color OutlHover;
sf::Color OutlActive;
public:
Button(float x, float y, float w, float h,
sf::Font* Font, std::string Text,
unsigned CharSize, sf::Color TextIdl, sf::Color TextHover, sf::Color TextActive,
sf::Color Idle, sf::Color Hover, sf::Color Active
,sf::Color OutlIdle, ,sf::Color OutlHover = sf::Color::Transparent,
sf::Color OutlActive = sf::Color::Transparent,
short unsigned Id = 0);
~Button();
const bool Pressed()const;
const std::string GetText()const;
const short unsigned& GetId()const;
void SetText(const std::string Text);
void SetId(const short unsigned Id);
void Update(const sf::Vector2f& MousePos);
void Render(sf::RenderTarget& target);
};
class DrpList {
private:
float Keytime;
float KeytimeMax;
sf::Font& Fnt;
gui::Button* ActivElmnt;
std::vector<gui::Button*> List;
bool ShowList;
public:
DrpList(float x, float y, float w, float h, sf::Font& Fnt, std::string List[], unsigned NumElemnt, unsigned DefIndex = 0);
~DrpList();
const bool GetKeytime();
void UpdateKeytime(const float& dt);
void Update(const sf::Vector2f& MousePos, const float& dt);
void Render(sf::RenderTarget& target);
};
}
#endif // !BUTTON_H
Gui.cpp
#include "Gui.h"
using namespace gui;
Button::Button(float x, float y, float w, float h,
sf::Font* Font, std::string Text, unsigned CharSize,
sf::Color TextIdl, sf::Color TextHover, sf::Color TextActive,
sf::Color Idle, sf::Color Hover, sf::Color Active
,sf::Color OutlIdle, sf::Color OutlHover, sf::Color OutlActive, short unsigned Id)
{
this->bStates = IDLE;
this->Id = Id;
this->Shape.setPosition(sf::Vector2f(x, y));
this->Shape.setSize(sf::Vector2f(w, h));
this->Shape.setFillColor(Idle);
this->Shape.setOutlineThickness(1.f);
this->Shape.setOutlineColor(OutlIdle);
this->Font = Font;
this->Text.setFont(*this->Font);
this->Text.setString(Text);
this->Text.setFillColor(TextIdl);
this->Text.setCharacterSize(CharSize);
this->Text.setPosition(this->Shape.getPosition().x + (this->Shape.getGlobalBounds().width / 2.f) - this->Text.getGlobalBounds().width / 2.f,
this->Shape.getPosition().y + (this->Shape.getGlobalBounds().height / 2.f) - this->Text.getGlobalBounds().height / 2.f);
this->TextIdl = TextIdl;
this->TextHover = TextHover;
this->TextActive = TextActive;
this->Idle = Idle;
this->Hover = Hover;
this->Active = Active;
this->OutlIdle = OutlIdle;
}
Button::~Button()
{
}
const bool Button::Pressed() const
{
if (this->bStates == ACTIVE)
return true;
return false;
}
const std::string gui::Button::GetText() const
{
return this->Text.getString();
}
const short unsigned& gui::Button::GetId() const
{
return this->Id;
}
void gui::Button::SetText(const std::string Text)
{
this->Text.setString(Text);
}
void gui::Button::SetId(const short unsigned Id)
{
this->Id = Id;
}
void Button::Update(const sf::Vector2f& MousePos)
{
this->bStates = IDLE;
if (this->Shape.getGlobalBounds().contains(MousePos)) {
this->bStates = HOVER;
if (sf::Mouse::isButtonPressed(sf::Mouse::Left)){
this->bStates = ACTIVE;
}
}
switch (this->bStates)
{
case IDLE:
this->Shape.setFillColor(this->Idle);
this->Text.setFillColor(this->TextIdl);
this->Shape.setOutlineColor(this->OutlIdle);
break;
case HOVER:
this->Shape.setFillColor(this->Hover);
this->Text.setFillColor(this->TextHover);
this->Shape.setOutlineColor(this->OutlHover);
break;
case ACTIVE:
this->Shape.setFillColor(this->Active);
this->Text.setFillColor(this->TextActive);
this->Shape.setOutlineColor(this->OutlActive);
break;
default:
this->Shape.setFillColor(sf::Color::White);
this->Text.setFillColor(sf::Color::Blue);
this->Shape.setOutlineColor(sf::Color::Green);
break;
}
}
void Button::Render(sf::RenderTarget& target)
{
target.draw(this->Shape);
target.draw(this->Text);
}
gui::DrpList::DrpList(float x, float y, float w, float h, sf::Font& Fnt, std::string List[], unsigned NumElemnt, unsigned DefIndex)
:Fnt(Fnt), ShowList(false), KeytimeMax(10.f), Keytime(0.f)
{
this->ActivElmnt = new gui::Button(
x, y, w, h,
&this->Fnt, List[DefIndex], 12,
sf::Color(255, 255, 255, 150),
sf::Color(255, 255, 255, 200),
sf::Color(20, 20, 20, 50),
sf::Color(70, 70, 70, 200),
sf::Color(150, 150, 150, 200),
sf::Color(20, 20, 20, 200),
sf::Color(255, 255, 255, 200)
sf::Color(255, 255, 255, 255),
sf::Color(20, 20, 20, 200));
for (size_t i = 0; i < NumElemnt; i++) {
this->List.push_back(new gui::Button(
x, y + ((i + 1) * h), w, h,
&this->Fnt, List[i], 12,
sf::Color(255, 255, 255, 150),
sf::Color(255, 255, 255, 255),
sf::Color(20, 20, 20, 50),
sf::Color(70, 70, 70, 200),
sf::Color(150, 150, 150, 200),
sf::Color(20, 20, 20, 200),
sf::Color(255, 255, 255, 0)
sf::Color(255, 255, 255, 0),
sf::Color(20, 20, 20, 0),i));
}
}
gui::DrpList::~DrpList()
{
delete this->ActivElmnt;
for (size_t i = 0; i < this->List.size(); i++) {
delete this->List[i];
}
}
const bool gui::DrpList::GetKeytime()
{
if (this->Keytime >= this->KeytimeMax) {
this->Keytime = 0.f;
return true;
}
return false;
}
void gui::DrpList::UpdateKeytime(const float& dt)
{
if (this->Keytime < this->KeytimeMax)
this->Keytime += 10.f * dt;
}
void gui::DrpList::Update(const sf::Vector2f& MousePos , const float& dt)
{
this->UpdateKeytime(dt);
this->ActivElmnt->Update(MousePos);
if (this->ActivElmnt->Pressed() && this->GetKeytime()) {
if (this->ShowList)
this->ShowList = false;
else this->ShowList = true;
}
if (this->ShowList) {
for (auto& i : this->List) {
i->Update(MousePos);
if (i->Pressed() && this->GetKeytime()) {
this->ShowList = false;
this->ActivElmnt->SetText(i->GetText());
this->ActivElmnt->SetId(i->GetId());
}
}
}
}
void gui::DrpList::Render(sf::RenderTarget& target)
{
this->ActivElmnt->Render(target);
if (this->ShowList) {
for (auto& i : this->List) {
i->Render(target);
}
}
}
Settings.h
#pragma once
#ifndef SETTINGS_H
#define SETTINGS_H
#include "State.h"
#include "Gui.h"
class Settings :
public State
{
private:
sf::Font Fnt;
sf::Texture BgTex;
sf::RectangleShape BackGrnd;
std::map<std::string, gui::Button*> buttons;
std::map<std::string, gui::DrpList*> drplist;
gui::DrpList* Dl;
void InitVars();
void InitBackGrnd();
void InitFonts();
void InitKeybinds();
void InitGui();
public:
Settings(sf::RenderWindow* window, std::map<std::string, int>* SupportedKeys, std::stack<State*>* states);
virtual~Settings();
void UpdateInput(const float& dt);
void Update(const float& dt);
void UpdateGui(const float& dt);
void RenderGui(sf::RenderTarget& target);
void Render(sf::RenderTarget* target = nullptr);
};
#endif // !SETTINGS_H
Settings.cpp
#include "Settings.h"
void Settings::InitVars()
{
}
void Settings::InitBackGrnd()
{
this->BackGrnd.setSize(
sf::Vector2f(
static_cast<float>(this->window->getSize().x),
static_cast<float>(this->window->getSize().y)));
if (!this->BgTex.loadFromFile("Resources/Images/BackGrounds/Menu/M2.png")) {
throw "Error:Main_Menu:Failed to load background texture";
}
this->BackGrnd.setTexture(&this->BgTex);
}
void Settings::InitFonts()
{
if (!this->Fnt.loadFromFile("Fonts/SPACEMAN.ttf")) {
throw("Error:Main Menu St::Couldn't load font");
}
}
void Settings::InitKeybinds()
{
std::ifstream ifs("Config/MMKeys.ini");
if (ifs.is_open()) {
std::string key = "";
std::string key2 = "";
int keyval = 0;
while (ifs >> key >> key2)
{
this->Keybinds[key] = this->SupportedKeys->at(key2);
}
}
ifs.close();
this->Keybinds["CLOSE"] = this->SupportedKeys->at("ESC");
this->Keybinds["Left"] = this->SupportedKeys->at("A");
this->Keybinds["Right"] = this->SupportedKeys->at("D");
this->Keybinds["Up"] = this->SupportedKeys->at("W");
this->Keybinds["Down"] = this->SupportedKeys->at("S");
}
void Settings::InitGui()
{
this->buttons["Exit"] = new gui::Button(
900.f, 880.f, 250.f, 50.f,
&this->Fnt, "Back", 50,
sf::Color(70, 70, 70, 200),
sf::Color(150, 150, 150, 250),
sf::Color(20, 20, 20, 50),
sf::Color(70, 70, 70, 0),
sf::Color(150, 150, 150, 0),
sf::Color(20, 20, 20, 0), sf::Color(70, 70, 70, 0));
std::string Li[] = {"1920x1080","800x600","640x480"};
this->drplist["Resolution"] = new gui::DrpList(800, 450, 200, 50, Fnt, Li, 3);
}
Settings::Settings(sf::RenderWindow* window, std::map<std::string, int>* SupportedKeys, std::stack<State*>* states)
:State(window,SupportedKeys,states)
{
this->InitVars();
this->InitBackGrnd();
this->InitFonts();
this->InitKeybinds();
this->InitGui();
}
Settings::~Settings()
{
auto it = this->buttons.begin();
for (it = this->buttons.begin(); it != this->buttons.end(); ++it) {
delete it->second;
}
auto it2 = this->drplist.begin();
for (it2 = this->drplist.begin(); it2 != this->drplist.end(); ++it2) {
delete it2->second;
}
}
void Settings::UpdateInput(const float& dt)
{
}
void Settings::Update(const float& dt)
{
this->UpdateMousePos();
this->UpdateInput(dt);
this->UpdateGui(dt);
std::cout << this->MousePosView.x << " " << this->MousePosView.y << "\r";
}
void Settings::UpdateGui(const float& dt)
{
for (auto& it : this->buttons) {
it.second->Update(this->MousePosView);
}
if (this->buttons["Exit"]->Pressed()) {
this->Endstate();
}
for (auto& it : this->drplist) {
it.second->Update(this->MousePosView, dt);
}
}
void Settings::RenderGui(sf::RenderTarget& target)
{
for (auto& it : this->buttons) {
it.second->Render(target);
}
for (auto& it : this->drplist) {
it.second->Render(target);
}
}
void Settings::Render(sf::RenderTarget* target)
{
if (!target)
target = this->window;
target->draw(this->BackGrnd);
this->RenderGui(*target);
}
The full error message:
'
Error LNK2019
unresolved external symbol "public: __thiscall gui::Button::Button(float,float,float,float,class sf::Font *,class std::basic_string<char,struct std::char_traits<char="">,class std::allocator<char> >,unsigned int,class sf::Color,class sf::Color,class sf::Color,class sf::Color,class sf::Color,class sf::Color,class sf::Color,class sf::Color,class sf::Color,unsigned short)" (??0Button@gui@@QAE@MMMMPAVFont@sf@@V?$basic_strin g@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@IV Color@3@22222222G@Z) referenced in function "private: void __thiscall Settings::InitGui(void)" (?InitGui@Settings@@AAEXXZ)
Project:
Star Fire
File:
F:\Star Fire SFML\Star Fire\Settings.obj
Line:
1
'
Everything works perfectly before video 48,a Lnk2019 occurs right after i put more parameters into the 'gui::Button();' constructor in 'Gui.cpp' specifically the 'sf::color::' OutlIdle - Hover and Active parameters. As soon as i put them in the error occurs.
Can someone help me ?
What I have tried:
I've tried to run the project in release mode instead and it works fine.The Error only appears in Debug.