I have the following files:
Source.cpp
#include "SFML\Graphics.hpp"
#include "SpriteControl.h"
using namespace sf;
int main(int argc, char ** argv){...}
SpriteControl.cpp
#include "SFML\Graphics.hpp"
#include "SpriteControl.h"
using namespace sf;
SpriteControl::SpriteControl(){}
SpriteControl::SpriteControl(Texture textureIn){
texture = textureIn;}
SpriteControl::~SpriteControl(){}
void SpriteControl::setMoveable(bool in) {
isMoveable = in;}
void SpriteControl::setVelocity(float vx, float vy) {
if (isMoveable) {
velocity.x = vx;
velocity.y = vy;
}
}
Vector2f SpriteControl::getVelocity() {
return velocity;}
SpriteControl.h
#pragma once
class SpriteControl{
Texture texture;
Sprite sprite;
bool isMoveable;
Vector2f velocity;
public:
SpriteControl();
SpriteControl(Texture textureIn);
~SpriteControl();
Vector2f getVelocity();
void setMoveable(bool in);
void setVelocity(float vx, float vy);
};
When I try to build, I get undeclared identifier errors for "texture" and "velocity", as well as "overloaded member function not found" for my constructor, "left of .x must have class/struct/union", "getVelocity is not a member of SpriteControl", and so on. An error for almost every line of both the SpriteControl.cpp and SpriteControl.h files, none of which make any sense. Any thoughts?
Note: the SFML libraries have all be linked properly. Earlier, simpler versions of the program without any header files compiled and ran just fine.
Related
I'm trying to create a 2D sidescroller mini-game. For now, I only have a character with a sprite and one animation, which i'm trying to move using the left/right arrows. At first, I only had a Character class, storing the sprite of the character and its running animation. And it worked. But now, I'm trying to add a CharacterManager class, which will create all the characters to avoid doing it in the main, and which will manage their movements and draw them.
And it doesn't work anymore. I think my problems come from the fact that I have trouble using pointers, which I'm not really familiar with.
Here are the different classes I'm using :
Animation.h :
#pragma once
#include <vector>
#include <SFML/Graphics.hpp>
#include <stdexcept>
#include <ctime>
#include "Constants.h"
class Animation {
public:
Animation();
~Animation();
void SetFrames(std::vector<sf::IntRect> frames) { m_frames = frames; }
sf::IntRect Play();
private:
std::vector<sf::IntRect> m_frames;
unsigned int m_currentFrame;
float m_updateTime;
float m_timeSinceLastFrame;
float m_lastCallTimestamp;
float m_currentTimestamp;
bool m_firstCall;
};
Animation.cpp :
#include "Animation.h"
Animation::Animation() {
m_currentFrame = 0;
m_updateTime = 1.0f / ANIMATION_SPEED;
m_timeSinceLastFrame = 0.0f;
m_firstCall = true;
}
Animation::~Animation() {
}
sf::IntRect Animation::Play() {
if (m_frames.size() == 0) {
throw std::length_error("The frames vector is empty");
}
// Advance time and add the elapsed time to timeSinceLastFrame
m_currentTimestamp = std::clock();
// Ignore elapsed time if first call
if (m_firstCall) {
m_timeSinceLastFrame = 0.0f;
m_lastCallTimestamp = m_currentTimestamp;
m_firstCall = false; // Not first call anymore
}
else {
m_timeSinceLastFrame += (m_currentTimestamp - m_lastCallTimestamp) / CLOCKS_PER_SEC;
m_lastCallTimestamp = m_currentTimestamp;
}
// Next frame
if (m_timeSinceLastFrame >= m_updateTime) {
m_currentFrame++;
m_timeSinceLastFrame = 0;
// Check animation end
if (m_currentFrame >= m_frames.size()) {
m_currentFrame = 0; // Reset frame progression
m_firstCall = true; // Next passage will be the first call of a new animation
/* TODO : return something to alert the end of the animation
(like a specific rectint or set a variable to true and get it on the other side) */
}
}
return m_frames[m_currentFrame];
}
Character.h :
#pragma once
#include<string>
#include<iostream>
#include <SFML/Graphics.hpp>
#include <vector>
#include <map>
#include "Constants.h"
#include "Animation.h"
class Character : public sf::Drawable {
public:
Character();
Character(std::string name);
~Character();
void Move(float value);
// Setters
void SetTexture(std::string filename);
void SetPosition(sf::Vector2f pos) { m_position = pos; };
void SetAnimations(std::map<std::string, Animation*> animations) { m_animations = animations; };
protected:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
std::string m_name;
unsigned int m_orientation; // 0 (default) = right | 1 = left
std::map<std::string, Animation*> m_animations;
Animation runningAnimation;
sf::Vector2f m_position;
sf::Texture m_texture;
sf::Sprite m_sprite;
};
Character.cpp :
#include "Character.h"
Character::Character() {}
Character::Character(std::string name) {
m_name = name;
m_orientation = 0;
runningAnimation = Animation();
}
Character::~Character() {
}
void Character::draw(sf::RenderTarget& target, sf::RenderStates states) const {
target.draw(m_sprite, states);
}
void Character::Move(float value) {
m_sprite.setTextureRect(runningAnimation.Play());
m_position.x += value;
m_sprite.setPosition(m_position);
}
void Character::SetTexture(std::string filename) {
filename = TEXTURE_FILES_PREFIX + filename;
// Load the entire texture file
if (!m_texture.loadFromFile(filename))
std::cout << "Error loading texture file : " << filename << std::endl;
// Set the texture (by default, initialize to idle state) and the position
std::vector<sf::IntRect> runningFrames{
sf::IntRect(67, 45, 19, 28),
sf::IntRect(116, 46, 20, 27),
sf::IntRect(166, 48, 20, 25),
sf::IntRect(217, 45, 22, 28),
sf::IntRect(266, 46, 19, 27),
sf::IntRect(316, 48, 20, 25)
};
runningAnimation.SetFrames(runningFrames);
m_sprite.setTexture(m_texture);
m_sprite.setTextureRect(runningAnimation.Play());
m_sprite.setPosition(m_position);
}
CharacterManager.h :
#pragma once
#include <vector>
#include <map>
#include <iostream>
#include <SFML\Graphics.hpp>
#include "AliveCharacter.h"
#include "Npc.h"
#include "Animation.h"
#include "CharacterStats.h"
enum CharacterType
{
NPC,
ALIVE,
GENERAL
};
// Class containing a vector of character entities and creates the animations of these entities from a data file (later)
class CharacterManager : public sf::Drawable {
public :
CharacterManager();
~CharacterManager();
// Loads the file and stores the content inside data string (not used for now)
void LoadDataFile(std::string filename);
// Create a character and add it to the list
void CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos);
void CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos, std::map<std::string, Animation*> animations);
void CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos, std::map<std::string, Animation*> animations, CharacterStats stats);
void Move(float value);
Character* GetCharacter(std::string name) { return m_characters[name]; }
private :
// Calls the draw() function of each stored Character
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
std::string m_data;
std::map<std::string, Character*> m_characters;
};
CharacterManager.cpp :
#include "CharacterManager.h"
CharacterManager::CharacterManager() {
m_characters = std::map<std::string, Character*>();
}
CharacterManager::~CharacterManager() {
//delete m_characters;
}
void CharacterManager::LoadDataFile(std::string filename) {
// TODO : load file content
}
void CharacterManager::CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos) {
Character new_character(name); // Create a generic character...
// ... and specialise it depending on the character type param
switch (characterType)
{
case NPC:
new_character = Npc(name);
break;
case ALIVE:
new_character = AliveCharacter(name);
break;
default:
new_character = Character(name);
break;
}
// Set texture, position and add to the characters list
new_character.SetTexture(textureFilename);
new_character.SetPosition(pos);
m_characters.insert({ name, &new_character });
}
void CharacterManager::CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos, std::map<std::string, Animation*> animations) {
CreateCharacter(textureFilename, name, characterType, pos);
m_characters[name]->SetAnimations(animations);
}
void CharacterManager::CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos, std::map<std::string, Animation*> animations, CharacterStats stats) {
CreateCharacter(textureFilename, name, characterType, pos);
m_characters[name]->SetAnimations(animations);
//m_characters[name]->SetStats(stats);
}
void CharacterManager::Move(float value) {
for each (std::pair<std::string, Character*> pair in m_characters) {
Character* character = pair.second;
character->Move(value);
}
}
void CharacterManager::draw(sf::RenderTarget& target, sf::RenderStates states) const {
for each (std::pair<std::string, Character*> pair in m_characters) {
Character* character = pair.second;
target.draw(*character);
}
}
And finally the Main.cpp, where you can see in comments the things I tried without success :
#include "Map.h"
#include "CharacterManager.h"
int main()
{
sf::RenderWindow window(sf::VideoMode(WINDOW_SIZE_X, WINDOW_SIZE_Y), WINDOW_TITLE);
window.setFramerateLimit(WINDOW_FRAMERATE);
Map map;
int pos = WINDOW_SIZE_X / 2 - MAP_SIZE_X / 2;
float movement = 0;
map.SetPosition(pos);
map.SetGroundTexture("Foreground/Tileset.png");
map.SetBackgroundTexture("Background/BGFront.png");
CharacterManager charManager;
charManager.CreateCharacter("main", "Characters/test-character.png", ALIVE, sf::Vector2f(400, WINDOW_SIZE_Y - HEIGHT_OF_GROUND - 28));
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
if (event.type == sf::Event::KeyPressed)
{
if (event.key.code == sf::Keyboard::Left)
movement = -MOVING_SPEED;
else if (event.key.code == sf::Keyboard::Right)
movement = MOVING_SPEED;
}
else if (event.type == sf::Event::KeyReleased)
movement = 0;
}
// Move the map
map.Scroll(movement);
//charManager.GetCharacter("main")->Move(movement);
charManager.Move(movement);
window.clear();
window.draw(map);
/*Character* mainPerso = charManager.GetCharacter("main");
window.draw(*mainPerso);*/
window.draw(charManager);
window.display();
}
return 0;
}
The error I'm getting is on the return m_frames[m_currentFrame] line in Animation.cpp, in the end of the Play() function. A pop-up window opens saying : "Expression: vector subscript out of range". This error only happens the second time the code goes through this line. The first time it's called from the SetTexture() function of Character.cpp (m_sprite.setTextureRect(runningAnimation.Play())), itself called from the CreateCharacter() function of the CharacterManager (new_character.SetTexture(textureFilename)), and at this point the Animation object looks as it should.
But the second time, it's called from the Move() function of Character (m_sprite.setTextureRect(runningAnimation.Play())), itself called from the Move() function of the CharacterManager (character->Move(value)). And at this point, all of the Animation object absolutely doesn't look like it should. In debug mode, I can see this :
Debug screenshot
As I said earlier, I think the problem comes from the use of pointers. When I'm trying to remove them, the code runs, but I get a white square problem.
I tried to find some sort of tutorial on how to use this kind of architecture, but didn't find anything relevant. If you know one, I'll be glad to look at it.
As I said earlier, I think the problem comes from the use of pointers.
When I'm trying to remove them, the code runs, but I get a white
square problem.
yep, it is a common issue for SFML when using Texture and Sprite when shallow copy is used.
Let's look at sf::Sprite::setTexture reference:
The texture argument refers to a texture that must exist as long as
the sprite uses it. Indeed, the sprite doesn't store its own copy of
the texture, but rather keeps a pointer to the one that you passed to
this function. If the source texture is destroyed and the sprite tries
to use it, the behavior is undefined.
So, a class like below, with default generated copy operation by compiler:
class Foo {
public:
void setT() {
// generate texture {t}
s.setTexture(t);
}
sf::Sprite s;
sf::Texture t;
};
will bring troubles to you. Because when a copy is made by Foo f(otherFoo);, sprite in newly created instance of Foo will have pointer to texture of otherFoo - it is shallow copy of pointer to sf::Texture. Deleting otherFoo will make a dangle pointer inside new constructed object.
In this case, you should implement assignment operation which makes deep copy of texture for sprite. If you don't know how to do it, you should mark assignment operations as deleted:
class Character : public sf::Drawable {
public:
Character();
Character(std::string name);
~Character();
// added
Character& operator=(const Character&) = delete;
Character(const Character&) = delete;
void Move(float value);
Then, compiler will give you an error for each attempt of copying of Character instance.
In case of deleted copy operation, you should rely on pointers. Your attempt failed, because you store pointer to local variables. Local variables are deleted at the end of a function scope, and referring to them later is undefined behaviour.
You have to create Character by operator new:
void CharacterManager::CreateCharacter(std::string name, std::string textureFilename, CharacterType characterType, sf::Vector2f pos) {
Character* new_character = new Character(name); // Create a generic character...
//...
// Set texture, position and add to the characters list
new_character->SetTexture(textureFilename);
new_character->SetPosition(pos);
m_characters.insert({ name, new_character });
}
I have problems to compile the following small code fragment. Visual Studio 2015 has problems in the deduction of the type of remover. Can someone explain me why and how to fix this error?
My idea was to create a reuseable function deleting the first occurence of a value in a given STL container under some user definable predicate.
#include <algorithm>
#include <iostream>
#include <iterator>
#include <functional>
#include <vector>
template<typename T>
auto removeOnlyOnce = [](std::vector<T>& v, const std::function<bool(const T&)>& pred) {
auto iter = std::find_if(v.begin(), v.end(), pred);
if (iter != v.end()) {
v.erase(iter);
}
};
int main(int argc, char** args) {
std::vector<int> v{ 1,2,3,4,2,2,3 };
// Works
std::function<bool(const int&)> isTwoPred = [](int x) { return x == 2; };
removeOnlyOnce<int>(v, isTwoPred);
// Also works
removeOnlyOnce<int>(v, [](const int x)->bool { return x == 2; });
// Gives compile error: C3538
// auto remover = std::bind(removeOnlyOnce<int>, v, std::placeholders::_1);
// remover([](const int x)->bool { return true; });
std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
}
The compiler issues the following warning:
main.cpp(26): error C3538: In einer Deklaratorliste muss "auto" immer in denselben Typ hergeleitet werden.
main.cpp(26): note: kann "<lambda_d00b55a1f2cac59f0efd4a81f45edea3>" sein
main.cpp(26): note: oder "std::_Binder<std::_Unforced,<lambda_d00b55a1f2cac59f0efd4a81f45edea3> &,std::vector<int,std::allocator<_Ty>> &,const std::_Ph<1> &>"
with
[
_Ty=int
]
Compiling with Wandbox and Option C++11 gives the following warning, which might be important:
prog.cc:8:6: warning: variable templates are a C++14 extension [-Wc++14-extensions]
auto removeOnlyOnce = [](std::vector<T>& v, const std::function<bool(const T&)>& pred) {
^
1 warning generated.
This lambda is not local. Please omit the & in [&] and you should be fine. Maybe a little cryptic, what I wrote: In other words, you don't have a this to capture.
I want to use transient scrollbar (Transient scroll bars appear when the content is scrolled and disappear when they are no longer needed) in Qt application. For this purpose I have inheritanced class QproxyStyle and reimplemented function styleHint. Code placed below.
File ScrollBar.h:
#include <QStyle>
#include <QCommonStyle>
#include <QProxyStyle>
class ScrollBarStyle : public QProxyStyle
{
public:
int styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *widget, QStyleHintReturn *hret) const;
};
File ScrollBar.c:
#include "ScrollBar.h"
int ScrollBarStyle::styleHint(StyleHint sh, const QStyleOption *opt, const QWidget *widget,QStyleHintReturn *hret) const
{
int ret = 0;
switch (sh) {
case SH_ScrollBar_Transient:
ret = true;
break;
default:
return QProxyStyle::styleHint(sh, opt, widget, hret);
}
return ret;
}
File MainWindow.h:
#include <QMainWindow>
#include <QTextEdit>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
};
File MainWindow.cpp:
#include <QTextEdit>
#include "MainWindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QTextEdit *l = new (std::nothrow) QTextEdit(this);
if (l == 0)
return;
setCentralWidget(l);
}
MainWindow::~MainWindow()
{
}
File main.cpp:
#include "ScrollBar.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
ScrollBarStyle *style = new (std::nothrow) ScrollBarStyle;
if(style == 0)
return -1;
style->setBaseStyle(a.style());
w.show();
return a.exec();
}
But I have got a problem: transient scrollbar has been appearing only once (when text doesn't fit in the text area) then it has been disappeared and never come back visible.
So how can I fix this problem?
Thanks!
You have forgotten to set the style to application.
a.setStyle(style);
I'm trying to implement a custom event in my wxWidgets application but I can't write the event table macros in a proper way.
the files that I use to implement the event is like the following:
the .h file
#ifndef __APP_FRAME_H__
#define __APP_FRAME_H__
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include <wx/evtloop.h>
#include "wxApp.h"
#include "sampleCefApp.h"
class appFrame: public wxFrame
{
public:
appFrame(const wxString &title, const wxPoint &pos, const wxSize &size);
private:
int OnExit();
void OnCefStartEvent(wxCommandEvent &e);
DECLARE_EVENT_TABLE()
};
#endif
the .cpp file
// File : appFrame.cpp
#include "appFrame.h"
wxDEFINE_EVENT(CEF_START_EVT, wxCommandEvent)
void appFrame::OnCefStartEvent(wxCommandEvent &e)
{
CefRunMessageLoop();
}
int appFrame::OnExit(){
CefShutdown();
Destroy();
return 0;
}
appFrame::appFrame(const wxString &title, const wxPoint &pos, const wxSize &size)
: wxFrame(NULL, wxID_ANY, title, pos, size)
{
}
wxBEGIN_EVENT_TABLE(appFrame, wxFrame)
EVT_COMMAND(wxID_ANY, CEF_START_EVT, appFrame::OnCefStartEvent)
wxEND_EVENT_TABLE()
And when I build my make file I get the following errors:
../src/appFrame.cpp:4:15: error: expected constructor, destructor, or type conversion before ‘(’ token
../src/appFrame.cpp:24:2: error: expected constructor, destructor, or type conversion before ‘wxEventTableEntry
I think the problem is related to mis-placing event table macros.
I want to know what is the problem exactly and how to fix it ?
You need a semicolon after wxDEFINE_EVENT() macro (as for almost all macros with wx prefix, they consistently require a semicolon, unlike the legacy macros without the prefix).
As usual, see the sample for the example of use of this macro.
I am writing an application using the OpenCV libraries, the Boost libraries and a pieve of code that I have downloaded from this LINK. I have created a project under the same solution with Thunk32 and I have the following files:
MainProject.cpp
#include "stdafx.h"
int main( int argc, char** argv )
{
IplImage *img = cvLoadImage( "C:/Users/Nicolas/Documents/Visual Studio 2010/Projects/OpenCV_HelloWorld/Debug/gorilla.jpg" );
Window::WindowType1 *win = new Window::WindowType1("Something");
cvNamedWindow( "window", CV_WINDOW_AUTOSIZE );
cvShowImage( "window", img );
cvSetMouseCallback( "oonga", (CvMouseCallback)win->simpleCallbackThunk.getCallback(), NULL );
while( true )
{
int c = waitKey( 10 );
if( ( char )c == 27 )
{ break; }
}
return 0;
}
Window.h
class Window {
public:
Window();
virtual ~Window();
//virtual void mouseHandler( int event, int x, int y, int flags, void *param );
private:
void assignMouseHandler( CvMouseCallback mouseHandler );
class WindowWithCropMaxSquare;
class WindowWithCropSelection;
class WindowWithoutCrop;
public:
typedef WindowWithCropMaxSquare WindowType1;
typedef WindowWithCropSelection WindowType2;
typedef WindowWithoutCrop WindowType3;
protected:
};
class Window::WindowWithCropMaxSquare : public Window {
public:
indev::Thunk32<WindowType1, void _cdecl ( int, int, int, int, void* )> simpleCallbackThunk;
WindowWithCropMaxSquare( char* name );
~WindowWithCropMaxSquare();
void _cdecl mouseHandler( int event, int x, int y, int flags, void *param );
private:
protected:
};
and Window.cpp
#include "stdafx.h"
Window::Window()
{
}
Window::~Window()
{
}
void Window::assignMouseHandler( CvMouseCallback mouseHandler )
{
}
Window::WindowWithCropMaxSquare::WindowWithCropMaxSquare( char* name )
{
simpleCallbackThunk.initializeThunk(this, &Window::WindowWithCropMaxSquare::mouseHandler); // May throw std::exception
}
Window::WindowWithCropMaxSquare::~WindowWithCropMaxSquare()
{
}
void _cdecl Window::WindowWithCropMaxSquare::mouseHandler( int event, int x, int y, int flags, void *param )
{
printf("entered mousehandler");
}
Now, when I run this, If I don't move the mouse inside the window, it's ok and the callback has been successfully passed to the cvSetMouseCallback function. The cvSetMouseCallback function has three parameters 1. the name of the window, 2. the CvMouseCallback and the NULL character. The CvMouseCallback is defined as
typedef void (CV_CDECL *CvMouseCallback )(int event, int x, int y, int flags, void* param);
and the CV_CDECL is just a redefinition of the _cdecl calling convention.
#define CV_CDECL __cdecl
Now, my mouseHandler function is a class member function, which I assume conforms to the _thiscall calling convention.
My question is, why do I get the following error just when I put my mouse on the window, if it has managed to get into the method at least once? I guess there's a change the second moment my mouse moves within the windoow. Can anyone help me please?
Here's an image with what I am doing:
That thunk code uses the __stdcall convention, not __cdecl. In this case, since cvSetMouseCallback takes a void* which it passes through to the callback, I would recommend that you use a static callback function and use this data pointer to pass the this pointer. You may then put your logic in this static function or else just call an instance version of the callback using the pointer that was passed in.
class Window {
public:
void _cdecl staticMouseHandler( int event, int x, int y, int flags, void *param ) {
((MouseHandler*)param)->mouseHandler(event, x, y, flags, NULL);
}
// ...
}
// ...
cvSetMouseCallback( "oonga", &Window::staticMouseHandler, win );