Houston, we have a problem. Here's a simplified code version:
main.cpp
#include <SFML/Graphics.hpp>
#include "global.hpp"
#include "init.hpp"
int main(void)
{
createWindow();
loadLevel();
while(window.isOpen())
{
if(!handleEvents()) window.close();
window.clear();
window.draw(bgSprite);
window.display();
}
return 0;
}
global.hpp
sf::Texture bgTexture;
sf::Sprite bgSprite;
init.hpp
void loadGraphics(void)
{
bgTexture.loadFromFile("bg.png");
bgSprite.setTexture(bgTexture);
}
Even though the texture and sprite variables are global, window screen remains black.
However, when I put the variables inside the main() function, everything works perfectly. Could someone explain why is this happening?
I thought that you can call global variables whenever and wherever you wish, and they will disappear only when the program itself terminates.
By the way, I also tried putting the variables and loadGraphics() right behind main() (not in a header file), still, no results. I also commented out all additional code, so the problem definitely lies here.
EDIT: I AM AN IDIOT!
I didn't call the loadGraphics(function). Thank You! I'm sorry for your wasted time. Everything started working correctly. Sad lol - spent over 1 hour fixing this thing...
You never call loadGraphics. Call that at the start of main, and your program will probably work.
But you'd almost certainly be better off without globals; and in any case, you don't want to define them in a header since that will break the One Definition Rule if you include that header more than once in your program.
If you really do want them to be global, then declare them (without definining them) in the header:
extern sf::Texture bgTexture;
and define them (as you've done) in just one source file.
Likewise, you shouldn't define a non-inline function in a header for the same reason. Either leave it in the header and make it inline:
inline void loadGraphics() // void parameter is pointless
{
bgTexture.loadFromFile("bg.png");
bgSprite.setTexture(bgTexture);
}
or just declare it in the header
void loadGraphics();
and move your definition into a source file.
You might avoid globals by encapsulating them in a class:
struct Graphics {
Graphics(std::string file) {
texture.loadFromFile(file);
sprite.setTexture(texture);
}
sf::Texture texture;
sf::Sprite sprite;
};
and instantiating this in main
Graphics graphics("bg.png");
//...
window.draw(graphics.sprite);
When you place a variable global to a project, you need to place it in a .cpp file and make a .h which declares it as extern. This allows for all the files to refer to the same global variable.
In your case, you'd change the code as so:
global.hpp
extern sf::Texture bgTexture;
extern sf::Sprite bgSprite;
global.cpp
sf::Texture bgTexture;
sf::Sprite bgSprite;
Also, as in Mike's answer, you never call loadGraphics().
Personally, I'd put that in another .cpp file and put a .hpp file with the prototype.
Also, when compiling, you'll have to compile all the cpp files together into a single executable (i.e. link them together)
bgTexture and bgSprite are never set. I don't see any call to your loadGraphics function in the main.
You should start by calling your loadGraphics function
Related
So, i have taken some ready code from a co-worker and build my own into theirs. The code compiles without warnings. The header contains a class and some declarations. The cpp file implements the methods. If i try to declare an extra method into the header file, there's absolutely no problem. But when i try to declare an extra variable (specifically char*) and use it into the cpp file, it compiles but creates abnormailites(programm does not do what it was doing, even with one declaration). If i declare the variable into the cpp file it works fine. I'm using dev c++. Is there maybe a linker issue?
this creates problems:
.h file:
class foo{
char* foo_char;
bool a_method();
}
.cpp file:
bool a_method(){
//do smthing
}
this is not:
.h file:
class foo{
bool a_method();
}
.cpp file:
char* foo_char;
bool a_method(){
//do smthing
}
Based on the initial writeup, I thought it might be an external variable declaration, but now we have sample code to work with. Let's assume this is real code.
This is the code from the latest edit of the question:
foo.h
class foo {
char* foo_char;
bool a_method();
}
foo.cpp
bool a_method() {
//do smthing
}
Okay, this is wrong. First, you need it to really be this:
bool foo::a_method() {
}
And your second example doesn't really make sense at all. You've moved your variable outside of the class definition, so it's no longer a class variable. Maybe that's what you want, but I don't think so.
And, of course, you still aren't indicating that a_method() is defined as a class method of foo when you write the code.
Try fixing this stuff and see if you do better.
Do you have a book? It seems to me you need to back up and read from the beginning. This is the very most basic parts of programming.
So, I'm trying to compile my code, but the compiler keeps complaining that "'mysnake' undeclared (first use this function)", but I declared it.
This is my Main.cpp, wehre it is declared.
#include "Class.h"
#include "Snake.h"
int main(int argc, char* args[]){
Prog run;
if((run.Init())==false){
return(1);
}
Snake mysnake;
if(run.LoadFiles()==false){
return(1);
}
run.MainLoop();
if(run.Draw()==false){
return(1);
}
run.CleanUp();
return(0);
}
And this is the file that makes the compiler complain (AFAIK it's the first file with any reference to 'mysnake' that gets compiled)
#include "Class.h"
#include<sstream>
#include "Snake.h"
bool Prog::Draw(){
std::stringstream message;
SDL_Rect position;
SDL_BlitSurface(image, NULL, screen, NULL);
int s=mysnake.EndSnake();
message<<"Your snake was "<<s<<" blocks long.";
msg=TTF_RenderText_Solid(font, message.str().c_str(), font_color);
if(msg==NULL){
return(false);
}
position.x=(WWIDTH-msg->w)/2;
position.y=(WHEIGHT-msg->h)/2;
SDL_BlitSurface(msg, NULL, screen, &position);
SDL_Flip(screen);
return(true);
}
I have thought about it for over an hour and I still can't understand why it does this. By the way I'm using Bloodshed Dev C++
I'd be very grateful for help.
Inside your Draw function there is no variable declared called mysnake. That function can't see the mysnake that's declared in main because it is local to main. You need to pass your mysnake object to the Draw function so that it knows which snake you're actually talking about.
To do that, give Draw an argument of type const Snake&, a "reference to const Snake" (or take away the const if EndSnake is a non-const member function):
bool Prog::Draw(const Snake& snake) {
// ...
}
And when you call Draw in main, do this:
run.draw(mysnake);
Now your Draw function has a variable called snake which was passed in from main. Because the argument is a reference, the Snake object that it sees is exactly the same object as in main. If the argument had been of type Snake instead of const Snake&, then you would get a copy of the mysnake from main.
Some extra advice:
We usually write conditions like (run.Init())==false as just !run.init() - it reads much better. Returning is also usually written as return true;, rather than return(true);, but that's up to you.
The fact that mysnake is declared in main does not allow one to use it in Prog. You probably want to transmit a reference to mysnake to the Draw method.
Through the constructor or through the call to the method.
Prog run(mysnake);
run.draw();
or
run.draw(mysnake);
I am attempting to make a fairly large video game, and my current method of handling mouse input is to pass mouseX, mouseY, and an enum mouseState as arguments to the update function of EVERY single object that requires knowledge of the mouse. It's fairly messy, and I want to make the mouse variables more global by putting them in a namespace called Input so that I can access them with Input::mouseX, et al.
As it stands now, The namespace Input exists in Input.h (contents below)
#pragma once
#include "allegro5\allegro.h"
#include "J_Enum.h"
namespace Input{
ALLEGRO_EVENT_QUEUE *inputQueue;
int mouseX;
int mouseY;
MOUSE_STATE mouseState;
void setUpInput();
void updateInput();
};
and the two member functions are defined in Input.cpp
#include "Input.h"
void Input::setUpInput(){...declaration
void Input::updateInput(){...''
Upon including Input.h in the main loop object's header Core.h the linker throws a hissy fit because in its eyes everything included in Input.h is now a Multiply Defined Symbol.
Clearly something is wrong with my use of header files, because to my knowledge, I haven't made any glaring mistakes in my use of namespaces and the error code prefix of LNK2005 seems to implicate the linker(?).
If anyone can possibly shed some light on my dilemma I would be most grateful
Declare the variables as extern:
// header file:
namespace Input {
extern int mouseX;
}
// implementation
#include "input.h"
namespace Input {
int mouseX;
}
I'm trying to write a header-only library of helper functions for myself. (I'm using boost and SDL, and boost is much easier to use, so I want to emulate that for my own helper library.)
I'm getting the error "Does not name a type" for one of my classes, and it's confusing me. I know I can get this problem with a misspelling or circular include, but can't find either of those problems in my code. Forward declaration in SdlWindow.cpp doesn't help. Including the header again (so I /do/ have a circular include) doesn't help either (I get "previously defined" errors).
Main.cpp:
#include <WBS/SdlWindow.hpp>
int main(int argc, char **argv) {
WBS::SdlWindow myWindow("Test window", 640, 480);
return 0;
}
SdlWindow.hpp:
#ifndef SDLWINDOW_HPP_
#define SDLWINDOW_HPP_
#include <string>
#include <SDL/SDL.h>
namespace WBS {
class SdlWindow {
public:
//Member Variables
SDL_Surface *screen;
int xSize;
int ySize;
//Constructor and Destructor
SdlWindow(std::string title, int xSize, int ySize);
virtual ~SdlWindow();
//Member Functions
};
}
#include "SdlWindow.cpp"
#endif /* SDLWINDOW_HPP_ */
And SdlWindow.cpp:
#include <string>
namespace WBS {
SdlWindow::SdlWindow(std::string title, int xSize, int ySize) {
this->xSize = xSize;
this->ySize = ySize;
SDL_Init(SDL_INIT_VIDEO);
screen = SDL_SetVideoMode(xSize, ySize, 32, SDL_ANYFORMAT);
SDL_WM_SetCaption("Simple Window", "Simple Window");
}
SdlWindow::~SdlWindow() {
SDL_FreeSurface(screen);
SDL_Quit();
}
}
The error I get is "SdlWindow' does not name a type", in SdlWindow.cpp, where I declare the two SdlWindow functions. What's causing this and how can I fix it?
I'm compiling with mingw32's gcc in Eclipse on Windows Vista.
I see what you are trying to do: a header-only library implies that .cpp file is included into .h file and not the other way around (this is, of course, confusing for many people). But if you are doing it that way, then you should not attempt to compile your .cpp files as ordinary source files. In fact, it might be a better idea to give your .cpp file a different extension: a .hpp maybe, for one example.
I suspect that you somehow managed to make SdlWindow.cpp a part of your project, i.e. you are trying to compile your SdlWindow.cpp by itself, as an ordinary source file. This will not work for obvious reasons. If your are trying to implement a header-only library, then no files from that library should be compiled as ordinary source files.
Of course, on an additional note, this whole thing will not work the way it looks now. A header-only library cannot contain non-inline non-template functions. It works for Boost because in Boost the functions are templates. Your functions are not templates. You have to declare them inline then, or otherwise you'll end up with multiple-definition errors for each of your functions.
You need to #include <WBS/SdlWindow.hpp> from SdlWindow.cpp.
You need to include WBS/SdlWindow.hpp from SdlWindow.cpp, as Sam said, but also you do not need to include SdlWindow.cpp from its header (that's a Bad Thing waiting to happen).
I've got 3 files that relate to this problem. file.h, file.C and user.C.
file.h has a private member, fstream logs.
In file.C's constructor it opens logs. It doesn't do this in the constructor, but the constructor calls a function OpenLog().
file.h also has an inline close function:
CloseLog() {if (logs) logs.close();}
The file user.C has an exit function which creates an instance of file, then calls CloseLog. It seg faults at this point. I created some other dummy tests, and it appears as though logs is lost in the mix somewhere ...
Going from file.C to user.C and then back to file.C causes this. If I have fstream logs as a global in file.C then it works - but I'd rather avoid a global.
Any thoughts on what I should do here? Please let me know if I should post more code about this, I can set up some dummy stuff to demo this better.
** Here's more code, as requested - I can't copy and paste, so forgive the lack of it please **
I will call the classes helpME.h, helpME.C and user.C
//helpME.h
#ifndef _helpME_H
#define _helpME_H
#include < iostream>
#include < fstream>
//various includes
class helpME {
private:
fstream logs;
public:
void CloseLog() {if (logs) logs.close();}
};
#endif
//end helpME.h
//helpME.C
void helpME::helpME(int argc, char** argv)
{
//various code
OpenLog();
}
void helpME::OpenLog()
{
//logname is set above, i had a print statement before that showed this is correct
logs.open(logname, ios::in | ios::out | ios::trunc);
}
//end helpME.C
//user.C
void user::quitHelpME(item)
{
helpME* hME = (helpME*) item;
hME->CloseLog();
}
//end user.C
Again - please forgive the lack of clarity, I'm thinking I may have just confused things more by adding this ... this code is on another box and can't be copied over.
void user::quitHelpME(item)
{
helpME* hME = (helpME*) item;
This doesn't create an instance, it's using C style casting to cast from whatever item is to a pointer to helpME.
if item is NULL then calling a method on it will seq fault.
otherwise still not enough detail in your example to give you an answer, the code present seems sound.
Because you've declared your variable in the .h file, you have two copies of it. The compiler doesn't 'see' .h files, it just copies/pastes what is in the file into the .C files, so, that's why you have two copies of the variable.
Declare the variable as extern in the .h file, and declare it again without the extern in only one .C file and don't use static in any declaration of that file.. It should fix your problem.