This is Camera class which responds to mouse movements.
class Camera {
public:
void processMouseMovement(double xPos, double yPos) {
//rotating camera
}
};
mouseEvent will be called when mouse is moved.
mouseCallbacks is a list of all functions that subscribe to mouseEvent.
#include<vector>
#include"Camera.h"
typedef void(__thiscall Camera::* mouseFunc)(double xPos, double yPos);
class InputSystem {
public:
static std::vector<mouseFunc> mouseCallbacks;
static void mouseEvent(double xPos, double yPos) {
//some processing
for (auto func : mouseCallbacks) {
func(xPos, yPos); //error here
}
}
};
//subscribe camera processMouseMovement to mouseEvent
std::vector<mouseFunc> InputSystem::mouseCallbacks{ &Camera::processMouseMovement };
Main funtion
#include<iostream>
#include"InputSystem.h"
Camera camera; //global camera object
int main() {
//simulating mouse event
InputSystem::mouseEvent(1.0f, 2.0f);
return 0;
}
This code gives me a compilation error.
term does not evaluate to a function taking 2 arguments
How can I call my function from function pointer func?
Is there any better way to store and call callbacks using function pointers?
Thanks
I've faced with The white square problem at SFML C++ while I'm trying to display a textured button. I've got an ImageButton.h which inherits from Button.h. The texture is loaded successfully (checked in debugger). But in the end, I see a white square. How to solve it?
Button.h
#ifndef BUTTON_H
#define BUTTON_H
#include<SFML/Graphics.hpp>
class Button
{
public:
Button();
Button(sf::Vector2f size, sf::Vector2f pos,sf::Color outlineColor, float sizeOutline);
void virtual draw(sf::RenderWindow* w) = 0;
protected:
sf::RectangleShape frame;
};
#endif // !BUTTON_H
Button.cpp
#include "Button.h"
Button::Button()
{
}
Button::Button(sf::Vector2f size, sf::Vector2f pos,sf::Color outlineColor, float sizeOutline)
{
frame.setPosition(pos);
frame.setSize(size);
frame.setOutlineColor(outlineColor);
frame.setOutlineThickness(sizeOutline);
}
ImageButton.h
#ifndef IMAGE_BUTTON_H
#define IMAGE_BUTTON_H
#include"Button.h"
class ImageButton : public Button
{
public:
ImageButton();
ImageButton(sf::Vector2f size, sf::Vector2f pos, sf::Color outlineColor, float sizeOutline, std::string path);
void draw(sf::RenderWindow* w);
private:
sf::Texture backTexture;
sf::Sprite background;
};
#endif // !IMAGE_BUTTON_H
ImageButton.cpp
#include "ImageButton.h"
ImageButton::ImageButton()
{
}
ImageButton::ImageButton(sf::Vector2f size, sf::Vector2f pos, sf::Color outlineColor, float sizeOutline, std::string path)
: Button(size,pos,outlineColor,sizeOutline)
{
backTexture.loadFromFile(path, sf::IntRect(sf::Vector2i(pos.x,pos.y),sf::Vector2i(size.x,size.y)));
backTexture.setSmooth(true);
background.setTexture(backTexture);
background.setPosition(pos);
}
void ImageButton::draw(sf::RenderWindow* w)
{
w->draw(this->background);
w->draw(this->frame);
}
programm.h
#ifndef PROGRAMM_H
#define PROGRAMM_H
#include<SFML/Graphics.hpp>
#include"ImageButton.h"
class programm
{
public:
programm();
void run();
private:
ImageButton b;
sf::RenderWindow* window;
sf::Event e;
void render();
void update();
};
#endif // !PROGRAMM_H
programm.cpp
#include "programm.h"
programm::programm()
{
this->window = new sf::RenderWindow(sf::VideoMode(600, 600), "Novel Editor", sf::Style::Close);
this->window->setPosition(sf::Vector2i(0, 0));
this->window->setFramerateLimit(60);
this->b = ImageButton(sf::Vector2f(50.f, 50.f), sf::Vector2f(50.f, 50.f), sf::Color::Yellow, 5.f, "images\\putin.png");
}
void programm::run()
{
while (this->window->isOpen())
{
while (this->window->pollEvent(e))
{
update();
}
}
}
void programm::render()
{
this->window->clear();
b.draw(this->window);
this->window->display();
}
void programm::update()
{
switch (e.type)
{
case sf::Event::Closed:
{
this->window->close();
break;
}
default:
break;
}
render();
}
Screenshot
programm::programm()
{
...
this->b = ImageButton(...); //< this line cause the bug
}
You are initializing your image button this->b by assigning from a local ImageButton. Now the sprite will have the texture reference of the local instance's texture, and when the local instance will "die" the texture will be freed. You need to maintain the lifetime of the texture
Solution 1: override the assignment operator and set texture there like this
ImageButton& operator=(const ImageButton& ref) {
backTexture = ref.backTexture;
background = ref.background;
background.setTexture(backTexture);
return *this;
}
Solution 2: Create a TextureManager and make it as your texture API for all your program, maintain your texture lifetime through it.
Solution 3: initialize the image button at programm constructor
programm::programm()
:b (sf::Vector2f(50.f, 50.f), sf::Vector2f(50.f, 50.f), sf::Color::Yellow, 5.f, "img.jpg")
{
...
}
Another bug
void ImageButton::draw(sf::RenderWindow* w)
{
w->draw(this->background);
w->draw(this->frame);
}
you're drawing your frame after the background, and your frame's fill color by default is white
Solution 1: draw frame first and draw background next
Solution 2: set your frame fill color alpha to 0
Button::Button(sf::Vector2f size, sf::Vector2f pos, sf::Color outlineColor, float sizeOutline)
{
frame.setPosition(pos);
frame.setSize(size);
frame.setOutlineColor(outlineColor);
frame.setFillColor(sf::Color(0, 0, 0, 0)); // <----
frame.setOutlineThickness(sizeOutline);
}
The problem you and others (on reddit,
on SO,
and elsewhere)
are facing is caused by the way the constructor and assignment operator of
sf::Sprite are (not) implemented: Since the developers decided to not
implement specialized functions and didn't make them private, the compiler
provides defaults that are not aware of the semantics of the m_texture
pointer and therefore doing a binary copy. This may be not the best approach but
it's documented.
So if you are using a sf::Sprite member in your class without taking
special measures for copying, the compiler will assume default assignment
semantics and therefore invoke the (invalid) assignment semantics of the
sf::Sprite class. The local ImageButton object you create in the
program invokes this default assignment of ImageButton
programm::programm()
{
this->window = new sf::RenderWindow(sf::VideoMode(600, 600), "Novel Editor", sf::Style::Close);
this->window->setPosition(sf::Vector2i(0, 0));
this->window->setFramerateLimit(60);
this->b = ImageButton(sf::Vector2f(50.f, 50.f), sf::Vector2f(50.f, 50.f), sf::Color::Yellow, 5.f, "images\\putin.png");
}
the Sprite in member b takes over the pointer texture from the
Sprite within the local ImageButton whose lifetime is limited to the
scope of the programm constructor. Beyond that, the sprite in your
member b holds a reference to a destroyed texture object which causes
is undefined behaviour (see also sf::Sprite Class Reference (SFML / Learn / 2.4.1 Documentation)):
If the source texture is destroyed and the sprite tries to use it,
the behavior is undefined.
By the way, I'd suggest directly using sf::RenderWindow window in the
program class not via pointer, so you could change your code to something
like this (note that I used button instead of b and shortened inlined
the implementation for the sake of brevity).
class programm
{
public:
programm():
window(sf::VideoMode(600, 600), "Novel Editor", sf::Style::Close);
button(sf::Vector2f(50.f, 50.f), sf::Vector2f(50.f, 50.f),
sf::Color::Yellow, 5.f, "images\\putin.png")
{
window->setPosition(sf::Vector2i(0, 0));
window->setFramerateLimit(60);
}
// ...
private:
// ...
sf::RenderWindow window;
ImageButton button;
};
Another option would be to provide a specialized assignment operator
(thakee nathees shows how)
or copy constructor for your ImageButton class that takes care of the
deep copy of the texture object.
Alternatively, you could think about implementing a wrapper class for
sf::Sprite to fix this issue and use this instead for you application(s).
I have the following classes:
//----------------------------------------------------------------------
// CHARACTER CLASS
//----------------------------------------------------------------------
class Character
{
private:
POINT2f char_position;
public:
VECTOR2f char_velocity;
Character();
~Character();
// Mutators
void SetChar_Position(POINT2f p);
void SetChar_Velocity(VECTOR2f v);
// Accessors
POINT2f GetChar_Position();
VECTOR2f GetChar_Velocity();
};
//----------------------------------------------------------------------
// PLAYER CLASS - INHERITED FROM "CHARACTER" CLASS
//----------------------------------------------------------------------
class Player : public Character
{
private:
public:
int health;
Player();
~Player();
void SetPlayer_Health(int h);
int GetPlayer_Health();
};
So essentially the player class inherits from the character class.
The Character class has member function which lets you set the characters position and velocity, which take in a POINT2f and VECTOR2f.
Within my main bit of code I create a player character Player Player1 and than set the balls velocity and position if a button is pressed:
if (ui.isActive('A')) // Check to see if "A" key is pressed
{
// Player Ball
Player1.SetChar_Velocity.x = -12.0;
Player1.SetChar_Position.x += (Player1.GetChar_Velocity.x*dt);
Player1.SetChar_Velocity.x += (acceleration*dt);
}
I'm currently getting errors that say left of .x must have class/struct/union, so I change Player1.SetChar_Velocity.x = -12.0; to Player1.SetChar_Velocity().x = -12.0; which than brings up the error expression must have class type and to few arguments in function call.
Does anyone know of a method that will allow my to only manipulate the x number of the char_velocity only. also I understand that my code to Set the .x velocity isn't correct because I'm not passing in a VECTOR2f value.
In order to achieve what you want to do, you will want the return type of you Get_ methods to be a reference (wiki). Your code will then look like
class Character
{
private:
POINT2f char_position;
public:
VECTOR2f char_velocity;
// Accessors
POINT2f& GetChar_Position() { return char_position; }
VECTOR2f& GetChar_Velocity() { return char_velocity; }
};
Also, it is often advised or required to be able to preserve const-correctness in your code, so you might want to add
const POINT2f& GetChar_Position() const { return char_position; }
const VECTOR2f& GetChar_Velocity() const { return char_velocity; }
This will allow you to do some calls like
POINT2f current_pos = a_char.GetChar_Position(); // const
a_char.GetChar_Velocity().x += 2; // non-const
Please note that it is often advised to pass the structures as const references instead of copies (although this might not hold true depending on your c++ version and your types, you can see this question for clarification), hence change your
void SetChar_Position(POINT2f pos) { char_position = pos; }
void SetChar_Velocity(VECTOR2f vel) { char_velocity = vel; }
to
void SetChar_Position(const POINT2f& pos) { char_position = pos; }
void SetChar_Velocity(const VECTOR2f& vel) { char_velocity = vel; }
My assignment is to derive a new class called Smiley from an existing class called Circle. I am using FLTK & C++.
Circle is:
struct Circle : Shape {
Circle(Point p, int rr) // center and radius
:r(rr) { add(Point(p.x-r,p.y-r)); }
void draw_lines() const;
Point center() const;
void set_radius(int rr) { set_point(0,Point(center().x-rr,center().y-rr)); r=rr; }
int radius() const { return r; }
private:
int r;
};
(The add method is a free method, not part of Circle)
And what I have created for Smiley so far is
class Smiley : public Circle {
public:
Smiley (Point p, int r) : Circle (a, r){
return;
}
};
I'm trying to figure out how to add circular eyes and a semi-circle mouth. I have an extremely vague idea of what the eyes should look like
Circle left_eye(Point(p.x - (r/3), p.y - (r/3)), (r/8)); //left eye
Circle right_eye(Point(p.x + (r/3), p.y - (r/3)), (r/8)); //right eye
But I don't even know how to incorporate it into my Smiley class, or if that's even the proper format. Help would be much appreciated, thanks.
You would push back your eyes onto a Vector_ref along with the mouth and the head and then create a function that draws each element of the vec_ref. Use a for loop in the drawing function (the drawing function should override the draw_lines() function from Circle)
I'm currently trying to write a button class. It takes 2 textures, m_texture and m_onHover, and its caption, which should be automatically centered. The function update() takes care of selecting the correct texture.
class button : public sf::Drawable
{
private:
const sf::Texture *m_texture;
const sf::Texture *m_onHover;
sf::Sprite m_sprite;
public:
button();
sf::Text m_caption; // public to allow easy formating, see centerCaption()
bool mouseIsOver() const;
void update();
void setPosition(sf::Vector2f position);
void setPosition(float x, float y);
void centerCaption();
// Access functions
void setTexture(const sf::Texture &texture) { m_texture = &texture; m_sprite.setTexture(*m_texture); }
void setonHoverTexture(const sf::Texture &texture) { m_onHover = &texture; }
void setCaption(sf::String text) { m_caption.setString(text); centerCaption(); }
void setFontSize(unsigned int size) { m_caption.setCharacterSize(size); centerCaption(); }
void setFont(sf::Font& font) { m_caption.setFont(font); }
private:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
};
bool button::mouseIsOver() const
{
if (m_sprite.getGlobalBounds().contains(sf::Vector2f(sf::Mouse::getPosition()))) // creating a float vector for contains() because getPosition gives int vector
{
return true;
}
else
{
return false;
}
}
Everything seems to be working, but the mouse position at which mouseIsOver() returns true seems to be moved 40 pixels above the sprite. The values in the rect from getGlobalBounds() seem to be correct when printed in the console.
Unluckily I dont have enough reputation to post a screenshot.
The cursor position should be translated to the proper coordinate system. Basically you need to use sf::RenderTarget::mapPixelToCoords (available in sf::Renderwindow by inheritance). For more details, have a look at the documentation and §Coordinates conversions of the official tutorial.
Also, you might want to consider making your button class inherit from sf::Transformable so that you don't have to manage the position/rotation/scale/... yourself. Have a look at Creating a SFML-like entity