Jump to content
  • Advertisement
Sign in to follow this  
jeffkiwi

Attempting a proper 2D game engine, always find myself out-of-scope

This topic is 633 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi again,
 
Over the past few months I've tried re-writing my program, several times in fact. Each time I run into a similar problem with scopes and modules that aren't able to interact. In my latest attempt, I made player into a class. I'm also using a graphics module to keep the ugly parts out of my main file. The problem is accessing the graphics class located in graphics.h/graphics.cpp - When I render my objects I'm in a for loop which seems to only access Tile but not Graphics
 
Example:
 
 

for (Tile& it : tileList) {


it.square.x = it.x;


it.square.y = it.y;


g.draw(g.wallgfx, g.Backbuffer, it.square); // square is an SDL Rect object for drawing on


};



g.draw(g.wallgfx, g.Backbuffer, &singleObjectName.square);


 
Of course it's not going to work. When I'm in the for loop I can't call the "g for graphics" object. The stand-alone line at the bottom works fine but I'm not going to make a specific object with its own name, for every detail in the game world! I could move the draw() function into tile.h or thing.h which Tile is derived from, but then (staying strictly with the engine concept) I have to call the backbuffer from graphics.h which is included in main.cpp but not available in tile.h
 
I know that I cannot #include graphics.h into both main.cpp and tile.h - I tried that a month or two ago!
 
This is disappointing because I spent a lot of time reading text books and tutorials, plus I asked many questions here. I'm 26 and I still don't understand how to 'modularise' a program in c++. I read Jazon Yamamoto's book but I haven't been able to replicate any of his complex code for my own use - his example code is a properly-written engine but it's too abstract for me to grasp. I could go back to including everything into my main file but that's exactly what I want to avoid. If PY-SDL2 is any good, then I might give that a try.

 

edit: added tags to post. Also note my use of QUOTE not CODE which allows for traffic light indication of good vs. bad code :)

Share this post


Link to post
Share on other sites
Advertisement
I know that I cannot #include graphics.h into both main.cpp and tile.h - I tried that a month or two ago!

 

 

You are absolutely allowed to include a header in both your main.cpp and another header file, though be wary of including in header files due to circular dependencies (two header files cannot include each other, either directly or indirectly). You're not allowed to because of said circular dependencies. You can avoid them by forward declaring classes instead of including them when you don't need to access any members and only need the definition of the type, and put your #includes in the .cpp file as often as possible rather than in the header.

Edited by cmac

Share this post


Link to post
Share on other sites

I'm not sure I'm understanding your issue correctly, but it sounds like the Singleton pattern would be a simple solution to your problem.
 
You are absolutely be allowed to include a header in both your main.cpp and another header file, though be wary of including in header files due to circular dependencies (two header files cannot include each other). You're not allowed to because of said circular dependencies. You can avoid them by forward declaring classes instead of including them when you don't need to access any members and only need the definition of the type, and by limiting your #includes to .cpp files as much as possible.


I think that explains it: have a master class which allows any derived class to be accessed from anywhere in the program.

 

In my programs I have only ever included .h files, never .cpp ... so this sounds like an esoteric concept to me. I'll look into it.

Share this post


Link to post
Share on other sites

In my programs I have only ever included .h files, never .cpp

Include the .h files, but include them in .cpp files when possible.

 

Forward declare when possible, include when you must. Look up forward declaring if you're not familiar with it.

 

Your master class sounds like a bad idea. It sounds effectively like a global, which is generally considered a code smell. If everything can access and talk to everything else from anywhere, tracking code flow becomes a huge issue as the project grows.

Share this post


Link to post
Share on other sites

I found some resources which appear to show exactly what I was after:

 

http://gameprogrammingpatterns.com/design-patterns-revisited.html

 

Above: singleton pattern explained in the context of games; and finally ...

 

... http://www.gamefromscratch.com/page/Game-From-Scratch-CPP-Edition-Part-5.aspx

 

Above, using GameObjectManager to manage objects by avoiding a for ranged loop, instead using while ... from within the GameObjectManager member function.

 

 

void GameObjectManager::DrawAll(sf::RenderWindow& renderWindow)

{
 
std::map<std::string,VisibleGameObject*>::const_iterator itr = _gameObjects.begin();
 
while(itr != _gameObjects.end())
 
{
 
itr->second->Draw(renderWindow);
 
itr++;
 
}
}

 

Share this post


Link to post
Share on other sites

Above, using GameObjectManager to manage objects by avoiding a for ranged loop, instead using while ... from within the GameObjectManager member function.

 

A ranged-for loop is essentially doing the same thing as the while loop. There's no particular reason to avoid it here; it is, in fact, less prone to error (due to fewer points of failure on your part) than the manual while version of the same loop.

Share this post


Link to post
Share on other sites
I know that I cannot #include graphics.h into both main.cpp and tile.h - I tried that a month or two ago!

There are two ways around this, which one works depends on the situation.

 

First way is to avoid defining the entire content of graphics.h more than once, as indicated by Khatharr. I'll just give it below too for completeness.

// graphics.h

#ifndef GRAPHICS_H
#define GRAPHICS_H

// definitions of graphics.h

#endif

The '#define' line defines the symbol 'GRAPHICS' the first time this file is included. Any next time it is included, the '#ifndef' line jumps to the end of the file, skipping all definitions.

 

The second way is only define existence of the Graphics class, but not its contents, by

class Graphics;

This says 'there is a class called Graphics'. The above is sufficient for declaring pointers or references to a Graphics object, like "Graphics *ptr" or "Graphics &g".

Typically you see this in a header file, where a function parameter is a pointer or reference to the Graphics object, like  "void f(Graphics &g);"

 

In the .cpp where you define the implementation of the function f, you then #include "graphics.h", so the compiler knows about the members of the Graphics class (and g.draw() works, for example).

 

 

 

This is disappointing because I spent a lot of time reading text books and tutorials, plus I asked many questions here. I'm 26 and I still don't understand how to 'modularise' a program in c++. I read Jazon Yamamoto's book but I haven't been able to replicate any of his complex code for my own use

This is a TV phenomenon, Yamamoto of course shows the solution that works, not the zillion solutions that don't work.

 

The reason that you fail however is not so much because you are so bad at it, but because the problem is complicated. The number of wrong solutions vastly outnumbers the number of good solutions, so statistically, you'll normally end in a bad solution without further knowledge. As you find reasons for failing, you iterate to the next attempts, avoiding the known fails you found so far (and then typically walk straight into the next one).

What it means is that you're still puzzling on the correct structure of the solution. If you get it right, all pieces will fit precisely.

 

 

 

Above: singleton pattern explained in the context of games; and finally

Singleton, as to avoid having a Graphics parameter? First intuition says it's a bad trade, but I haven't seen the code, and the devil is in the details, as always.

 

 

 

using GameObjectManager to manage objects by avoiding a for ranged loop, instead using while

I agree with Josh Petrie that it shouldn't make a difference, but it does for you apparently, so something happens in some way. Could you give more details what problem gets solved by the 'while' ? (or even why the problem with the 'ranged loop' doesn't happen with 'while').

Edited by Alberth

Share this post


Link to post
Share on other sites

Could you give more details what problem gets solved by the 'while' ? (or even why the problem with the 'ranged loop' doesn't happen with 'while').


I've likely got the wrong idea in my head - I thought that scopes were handled differently (while versus for). A for-loop has its own scope/namespace, like a virtual container within the program, the same thing with functions. I thought while loops were different, because I can declare something immediately prior to the while loop, and access that data from within the while loop without needing to pass a value or reference.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!