• Advertisement
Sign in to follow this  

Is it better to use extern or pass in a pointer (C++)

This topic is 2354 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

My camera class needs to know about my level class for example.

Is it better to use extern level; for example or to create a pointer to a level object and set this pointer with function (setLevel(Level level);

is either "better" ? or is there specific reasons to choose between the two methods?

thanks,

Share this post


Link to post
Share on other sites
Advertisement

My camera class needs to know about my level class for example.

Is it better to use extern level; for example or to create a pointer to a level object and set this pointer with function (setLevel(Level level);

is either "better" ? or is there specific reasons to choose between the two methods?

thanks,


What does the camera need to know about the level? It happens easily that one creates this kind of links between objects for some little thing even if the classes aren't really related.

Otherwise "SetLevel(...)" doesn't sound bad compared to the global variable.

Cheers!

Share this post


Link to post
Share on other sites
It depends a lot on how complicated your program is and if you need to have others maintain the code (or if you anticipate maintaining it years from now). In most cases, it's just a bad idea to use globals if you can avoid it. kauna has the right idea though: even if you're not using globals you should make sure that your class dependencies are as well defined and simplified as possible.

I've found that even for relatively simple programs global variables can make life difficult. I find that I frequently shadow variables without knowing it (by reusing a global variable name in a local variable declaration), or forget that I have a global variable and pass it in under an aliased name as a parameter, or a dozen other bad things. It doesn't make the program any less correct, but it does make it notably harder to maintain.

Share this post


Link to post
Share on other sites
Extern is almost always a bad idea and unnecessary, more so than goto.

But you probably don't want either one.

Your camera is nothing to do with the level, so your basic idea is skewed a bit.

What you probably need is some static method you call to get the current level, as this will come up over and over making games.

So you have Level::getCurrentLevel() or you might have a LevelManager class that has the info which seems to be popular way to do things.

Share this post


Link to post
Share on other sites
The others have already given the correct answer(s), but I want to draw special attention to one issue: If your camera class needs to know about your level, you are doing it wrong. That is a promise.
There is no reason for it, ever.
Likewise, a level never has any idea what a camera is. There are no conditions which could cause these two objects to know about the other.

Instead, one possible way to go (not exactly the way I would choose but certainly more appropriate) would be to have a camera that knows about certain non-specific data structures that it can use to speed up culling and therefor rendering, and the level just so happens to have these structures in it.
Then the camera knows only about a few generic structures, and any object, be it a level, a building interior, terrain, etc., can have these structures as part of their overall data.
And since there is still no logical reason a camera would know what a level is or vice-versa, the level would not be giving this data to the camera directly. The scene manager knows what both a level and a camera are and is responsible for sending whatever data needs to be sent to the camera from the level.
The camera doesn’t care from where the data came, and has no illogical dependencies.

In my example here, the camera is still doing a bit more than it should, but this puts you on a better track.

I've found that even for relatively simple programs global variables can make life difficult. I find that I frequently shadow variables without knowing it (by reusing a global variable name in a local variable declaration), or forget that I have a global variable and pass it in under an aliased name as a parameter, or a dozen other bad things. It doesn't make the program any less correct, but it does make it notably harder to maintain.

I am glad to see that you found globals difficult to maintain, but I am afraid it is for the wrong reason.
Standard naming conventions prevent name clashes. Globals typically start with g_, class members with m_, etc.
If you find yourself clashing names, you should think about how to prevent clashing of names (ala naming conventions).

However globals still cause a mess of code in most cases. In my newbie days I found myself #include’ing files just to get access to a global. But that file had a lot more in it than just the global, so my translation units were linking to a lot more information than they needed and making illogical connections. And, being a lazy newbie, I sometimes made use of those connections just because it was convenient. Sometimes I would add another global to that file so that one of my other sub-systems could augment how it worked with the original global, and suddenly every other system using that main global suddenly knew about the new global too, for no reason.
Circular dependencies and hackish work-arounds were not long to follow.

Naturally, I was excessive in my mistakes. Using globals does not mean you have to be as retarded with them as I was, but in the end there is still one common truth: The most simplistic connection between modules is via class declarations, not class instances. That is, by #include’ing only the class declaration, you are including only the bare amount of information you need, and this is always a better choice when your goal is to keep things as modular as possible.


Globals are still necessary for some things, but my approach is much more logical and adheres to the idea of #include’ing only the bare necessities.
My globals are actually static class members. Why is this better?
#1: It offers you the chance to make some hidden (as most are) and some public. Declaring a global inside a translation unit (not a header) may be valid, but given the choices, explicitly marking a global as “protected” or “private” really just seems more organized and logical. It also prevents hiding the fact that the global exists. I really prefer to look only at one header file to be able to determine, without exception, what things are declared.
#2: The “global” then becomes part of the class declaration. That means you are still only including the same file you would with the alternative, but only that file, and not a second file containing a global instance of that class.
#3: And because it is logically tied to that class declaration, no one will be tempted to add anything to that file that is not directly related to that class declaration. In the system I had used before, I had the class declaration and then another file for a global instance of that class. My global was not meant to be used specifically by any sub-system. I just thought of it as “whatever needs the main instance of this class can get it by #include’ing this file.” That flawed logic in itself lead to the spaghetti code that followed, but that cannot happen when a global is a static member of a class. It simply changes how people view the scope of the static member/global and no one will ever be tempted to add unrelated code/data to that file.
#4: Because of #3, you yourself will make better choices when deciding when and how to use globals. You won’t be putting a global there that is meant to be used by whatever needs a main instance of something. You will be putting static members/globals there because they are necessary for the basic workings of that class. This will hopefully make you think harder about when and where it is appropriate to use a global meant for random access. If you ever discover that case, please tell me. I still have not found any good reason to do so, and my code has been very clean and maintainable since dropping that idea.


L. Spiro

Share this post


Link to post
Share on other sites
You can move any global into a static class member.

I constantly have to use other people's code that define a ton of constants as enums. Then the names change or disappear so I get a compiler error and NO idea what the thing is, why I have to pass it in (also terrible design), or even where it was declared. Who knows.

If instead you had something simple like

struct ColorConstants
{
static const long RED = 0;
static const long GREEN = 1;
static const long BLUE = 2;
}

it's easy to deal with changes, easy to fid the declaration, and totally avoids name clashes (and relying on just naming conventions alone is not going to be enough for a big complicated project).

Share this post


Link to post
Share on other sites
YogurtEmperor's wall of text holds truth. Read it again. In particular, I want to quote
[color=#1C2837][size=2]
one possible way to go (not exactly the way I would choose but certainly more appropriate) would be to have a camera that knows about certain non-specific data structures ... any object, be it a level, a building interior, terrain, etc., can have these structures as part of their overall data.
And since there is still no logical reason a camera would know what a level is or vice-versa, the level would not be giving this data to the camera directly. The scene manager knows what both a level and a camera are and is responsible for sending whatever data needs to be sent to the camera from the level.
The camera doesn’t care from where the data came, and has no illogical dependencies.[/quote]I am doing exactly this. Cameras are opaque blobs, only the scene manager knows about them, it pulls out the info required by the world-drawing routines and sends the info by using an appropriate call.
[color=#1C2837][size=2]+1

Share this post


Link to post
Share on other sites

You can move any global into a static class member.

I constantly have to use other people's code that define a ton of constants as enums. Then the names change or disappear so I get a compiler error and NO idea what the thing is, why I have to pass it in (also terrible design), or even where it was declared. Who knows.

If instead you had something simple like

struct ColorConstants
{
static const long RED = 0;
static const long GREEN = 1;
static const long BLUE = 2;
}

it's easy to deal with changes, easy to fid the declaration, and totally avoids name clashes (and relying on just naming conventions alone is not going to be enough for a big complicated project).

I'd prefer:

namespace SomethingColor
{
enum ColorConstants
{
RED,
GREEN,
BLUE
};
}

Identical syntax. Less worries about maintaining a set of unique integers. No weird object that somebody could instantiate.

Share this post


Link to post
Share on other sites
I'm with Slavik81 on this one; in C++ if you are putting static members in classes you might want to consider a namespace instead.

Hell, with a namespace you can even have private global data if needs be, something I've used before.

[source]
// header

namespace Foo
{
void barSet(int value);
int barGet();
}

// cpp

namespace Foo
{

namespace
{
int barValue;
}

void barSet(int Value) { barValue = value; }
int barGet() { return barValue; }
}
[/source]

God aweful example but you get the idea...

Yes, it's 'global state' but it does have its uses.

Share this post


Link to post
Share on other sites
The reason I was passing the level to the camera was because the camera wants to test collisions against the level. So the camera calls a function in the level whch tests for collision using th given arguments, cameras position etc.

I cant understand how I could do this without letting the camera know about the level?

Share this post


Link to post
Share on other sites
Bounding box checks need to be done to remove objects that are not in the view frustum. Yes, this needs to be done, but why would you make the camera do it?
The camera’s job is to use its own camera data to create view and projection matrices, which in turn causes the image of your world to be projected onto your screen based off where the camera is and what its camera-specific settings are (field of view, aspect, etc.)

Your flawed logic stems from thinking the camera does anything more than this (though you can inherit from your basic camera to add functionality suitable for FPS games etc., but even here you are just adding controls to it and not extending its scope of visibility). As you grow in experience you will be able to more properly evaluate what jobs and information certain classes/objects should do/have.


Now, what information is needed in order to cull objects from view?
#1: A view frustum. This is composed of 6 planes.
#2: Object bounding boxes. AABB or OBB, who cares.
#3: Probably a quad tree or octree. Some way to partition space. This is technically even optional, but it does help performance a lot.

I mentioned a frustum, which is a general-purpose structure (not used specifically just for cameras) made by planes, which are also general-purpose (not used only by frustums).
AABB’s and OBB’s are also general-purpose structures.
All of these structures so far could fit fine into a base module designed to facilitate math functions or collision-detection structures etc. So far, no knowledge of a level has entered the picture at all.


Let’s think about where these structures are located.
Camera frustum: Should it be part of the camera itself? This is typically how it is done. Since the frustum only changes when the camera moves, and that is only once per frame at most, the typical way to go is to have a camera that knows about its own view frustum and updates it once per frame. Other objects can access it in order to perform frustum culling.

AABB’s/OBB’s: Should these be part of the level?
NO. They should be part of the objects that own them. A frustum is a bounding box for a camera, which the camera updates on its own once per frame. Entities with AABB’s or OBB’s should do exactly the same.

Quad tree/octree: How about these? Part of the level?
NO. The scene manager is the manager of the game world. It should be responsible for managing the tree. Entities can take themselves out of the tree and put themselves back in just fine. The entities can know what an octree is because it is again a generic structure that does not endow the entity with completely unrelated information.
But the scene manager needs to give them an octree into which to insert themselves, and it needs to tell them when to do so (since objects may move temporarily many times per frame, it would be wasteful to update the octree every time, so once again it should only be done once per frame).



Seems this “level” thing is pretty useless.
In fact, it is. There is no real concept of a level. What makes up a level? A skybox, piece of terrain, some buildings, and interactive characters?
Being so specific is harmful. What happens when you make your editor and there is no terrain or skybox?


The term we use is a “scene”. Inside a scene, it doesn’t matter how many or few characters or objects there are. It doesn’t matter if there is terrain or not. No skybox? No biggie.

Now that the concept of a level is thrown out, and a new term introduced, you might have figured out what is responsible for performing frustum culling: The scene manager.
The scene manager has the octree and can run down it however it pleases to collect objects. It also happens to be the one being that can know about all the types of objects in your game world (cameras, 3D meshes, terrain, etc.) without overstepping the boundaries of what it should know.
For a camera to know about the terrain or for the terrain to know about the camera is a sin.


So, the entities have information about their bounding boxes. The camera has information about its frustum. Neither of them use that information (well not here).
The scene manager takes the frustum from the camera, runs through its octree, checks the bounding boxes of all the entities it finds, and compiles the list of visible objects.

Simple, huh?


By the way, just because the scene manager used the frustum of the camera to run its trace through the octree does not mean its trace through the octree requires a camera. It requires a frustum. It doesn’t matter that the frustum came from a camera, so don’t make your implementation rely on a camera. The frustum could have come from anywhere.
Do yourself one better and make your implementation rely on a k-DOP. A frustum is a specialized case of a k-DOP. If you take a general k-DOP as input you can use the same function for culling objects for shadow mapping.


L. Spiro

Share this post


Link to post
Share on other sites
Thanks for the the really detailed help with this. My frustum culling is done exactly as you described so its good to know I was on the right track.

My level geometry is created from bsp. So the reason I had been passing the level to the camera was to test collisions with the level geometry and the camera. So for example if the camera collides with the wall you wont pass through the wall but you will stop.

So currently the camera knows about the .bsplevel object and calls a function in the .bsplevel to test collisions against it.

I cant see any way that I could do this without the camera knowing about the bsplevel

So would the correct way to organise this be to still pass the bsp object to the camera so that the camera can collide with the world but to not think of the bsp as the level and make sure all other objects like meshes, skybox whatever are handled outside of the bsp, in the "scene manager" ?

Share this post


Link to post
Share on other sites
By the sounds of things your camera class is doing too much; it should only be doing the things it needs to do to be a camera in the world. So holding position, FoV, direction etc and a reference to a bounding box for collision reasons (assuming a 3rd person camera; a 1st person camera would depend upon the collision hull the player is using).

There is no need for the camera to even be aware it is in a world, it certainly should't be responding to input directly or reacting to collisions. Instead this should be dealt with in higher logic, where other piece of logic which is aware of the camera and, to some degree, the collision world it lives in, attempts to move the camera and reacts to the collision event to reset it.

Single Responsibility Principle is key here; never have a class do more than it needs to in order to be what it represents.

Share this post


Link to post
Share on other sites
Yeah I agree too any culling or especially game logic like running into a wall and stopping should not be in the camera.

As for the level yogurt emeror describes the typical arrangement but for many things you can have a variety of designs. The most general arrangement can also be the least easy to use so I would not go crazy trying to make everything too generalized when you are really making one game not an engine for other people's use. I can't count the times I will be annoyingly traversing a tree to find the SINGLE geometry element for an object, for example.

Share this post


Link to post
Share on other sites
Ok I see, so the correct way to do this would be to have a scene manager class that has an instance of the camera and an instance of the level geometry and then uses the data in the camera object to test for collisions in the level geometry object?

never have a class do more than it needs to in order to be what it represents[/quote]

thats really well put I will keep that in mind from now on.

Share this post


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

  • Advertisement