SFML community forums

Help => Graphics => Topic started by: lorence30 on May 22, 2015, 08:10:18 pm

Title: cannon and bullet
Post by: lorence30 on May 22, 2015, 08:10:18 pm
what would be the best idea to write cannon and bullets?


class Cannon{};
class Bullet : pubic Cannon{};

or write them separately?
class Cannon{};
class Bullet{};
Title: Re: cannon and bullet
Post by: Jesper Juhl on May 22, 2015, 08:20:57 pm
When you inherit from a class you should usually think of it as having a "is a" relationship. When you instead use composition you should think of a "has a" relationship.

So, when you say "class Bullet : public Cannon" you are, in a way, saying "a bullet IS A cannon" - which is clearly false.

If instead you make them different standalone classes (which makes sense since they are clearly two different things) and then make the Cannon contain containers of Bullet(s), then you are saying " a cannon HAS A bullet" - which makes sense.

PS: how is this SFML related???
Title: Re: cannon and bullet
Post by: lorence30 on May 22, 2015, 08:29:53 pm
i also thought for inheritance like, "cannon needs bullet to fire , okay it needs to inherit cannon".
and since cannon needs singleton


@Jesper Juhl thanks i get your point, that was fast reply.
Title: Re: cannon and bullet
Post by: Hapax on May 22, 2015, 08:30:45 pm
PS: how is this SFML related???
or graphics related!
Title: Re: cannon and bullet
Post by: Jesper Juhl on May 22, 2015, 08:47:45 pm
and since cannon needs singleton
Right there I died a little inside :(
Please, please don't use the Singleton pattern. It is an anti-pattern. It has all the problems of global variables and more and no real advantages. It will bite and hurt you. Just say no!
Title: Re: cannon and bullet
Post by: shadowmouse on May 22, 2015, 08:50:34 pm
Is it just as bad when you declare a class normally and fill it with variables that need to be passed to a group of functions, then just define a single instance of that class, rather than specifically restricting it to one, and it is created in main? Is there a problem with that?
Title: Re: cannon and bullet
Post by: lorence30 on May 22, 2015, 09:32:49 pm
okay thanks guys, now i know.
Title: Re: cannon and bullet
Post by: Jesper Juhl on May 22, 2015, 09:34:55 pm
What you lose with global variables (and singletons which you can generally consider to just be glorified globals) is control over when they get created (and destroyed) compared to other objects (remember; creation order of globals is only defined within a single compilation unit). So, if multiple globals (or singletons) depend on each other you have trouble on your hands.
Also, when do globals (and singletons in general) get destroyed? When you leave main and global dtors are run, that's when. At that point in time you again face a problem since destruction order is (again) only well defined for objects within a single compilation unit and additionally, if your destructor wants to do anything non-trivial it now has to do this in a world where we've left main and a lot of assumptions about the world are generally not valid. That is, if your destructor even gets run at all (singletons are commonly heap allocated and leaked at exit).
Then you also have the problem that globals/singletons increase coupling between your classes and it becomes difficult to reason about the overall state of the system since anyone could be changing the global at any time.
If you are using threads it gets even worse since you now have to ensure that creation/destruction of the global/singleton is atomic with respect to other threads and ensure that changes to the global state is properly synchronized.
Globals/Singletons just land you in a world of hurt and you are better off just avoiding them like the plague (unless you have really, really good reasons and really know what you are doing and why - which is very rarely the case).

Edit: there are more potential problems, but the best way to learn is to do. So I invite you to try and use a lot of globals and singletons in a real (100K+ lines of code) application and then come back and tell me how many weird crashes and other issues you had and how much debugger time you had to spend. I'll bet you a beer that most of those issues/time were caused by the globals/singletons.  Go ahead, try it. I have and I have the scars to prove it. That way lies madness.
Title: Re: cannon and bullet
Post by: Nexus on May 22, 2015, 10:12:19 pm
What Jesper Juhl said cannot be emphasized enough. There are many games using those dubious manager classes for anything, whose responsibility and scope is so vague that they cannot even be named meaningfully. Even worse, they're mostly implemented as singletons.

People think they've found a simple and great design "because you don't have to pass the parameters to every function" (which you don't have to otherwise either, btw). At one point the project exceeds a certain complexity, and the initially saved time strikes back, with a force hundred times bigger than you'd expect (Jesper's scars prove it). A while ago I also listed some reasons (http://en.sfml-dev.org/forums/index.php?topic=5187.msg34227#msg34227) why singletons should be avoided as a general-purpose pattern in game development. Four years later, they still apply literally.

Just recently I had to maintain an older codebase with those cool singleton managers. The master of those managers initializes the others, who are later accessed indirectly via the master. Now, an object initialized during master initialized dared to access a manager. This lead to a line static Singleton instance; before that instance finished construction. This worked perfectly well on one compiler. When porting the project, things would freeze in a deadlock because this compiler handles initializations of static variables differently. Well, you can imagine how funny it was to track down the cause. Of course, things were hidden deep down in a class where the global circular access was everything but obvious. And here, we're talking about deterministic, reproducible bugs... I don't even want to start with multithreading in combination with global/static variables.


Is it just as bad when you declare a class normally and fill it with variables that need to be passed to a group of functions, then just define a single instance of that class, rather than specifically restricting it to one, and it is created in main? Is there a problem with that?
That's the way you usually do it -- why should it be bad?
Except that in bigger projects, you probably won't use main() for that...
Title: Re: cannon and bullet
Post by: Jesper Juhl on May 22, 2015, 10:44:44 pm
Thank you for that validating post Nexus.
Spoken like a true - battle hardened - veteran :)
Title: Re: cannon and bullet
Post by: shadowmouse on May 22, 2015, 10:56:32 pm
Is it just as bad when you declare a class normally and fill it with variables that need to be passed to a group of functions, then just define a single instance of that class, rather than specifically restricting it to one, and it is created in main? Is there a problem with that?
That's the way you usually do it -- why should it be bad?
Except that in bigger projects, you probably won't use main() for that...
Thank you, it's just that when I was first using OOP, the first way it occurred to me to do things is as above and then I heard about singletons being a bad idea and this sounded to me like any class which is designed so that it only makes sense to have one instance is a bad thing, for example I almost always have a brain class that holds all of the fundamental variables and handles background functions and I've always had a nagging doubt that the don't use singletons advice could apply to that sort of thing, even though it's just a normal class (or struct) first instanciated at the start of main().
Title: Re: cannon and bullet
Post by: Jesper Juhl on May 22, 2015, 11:07:35 pm
The fact that you instantiate it inside main (not in global scope) makes a world of difference. You now have control of its lifetime and order of creation compared to other objects and it gets destroyed inside a scope (main) where the world is still (supposed to be) sane.
Title: Re: cannon and bullet
Post by: Nexus on May 22, 2015, 11:07:58 pm
Jesper: tough battle eh? 8)

[...] and this sounded to me like any class which is designed so that it only makes sense to have one instance is a bad thing
There are many classes of which there exists only one instance at a time, simply because of the nature of the concept they represent: application, game, world, camera...

for example I almost always have a brain class that holds all of the fundamental variables and handles background functions and I've always had a nagging doubt that the don't use singletons advice could apply to that sort of thing, even though it's just a normal class (or struct) first instanciated at the start of main().
Depending on what your brain class does, it may be built upon a different anti-pattern: god class (too many responsibilities). Your failure to describe it concretely ("fundamental variables and background functions") is a strong indicator for that :P

What is it for? Maybe it can be split into different classes and functions. In any case, it does not suffer from the same problems as singleton ;)
Title: Re: cannon and bullet
Post by: Jesper Juhl on May 22, 2015, 11:11:22 pm
Jesper: tough battle eh? 8)
Yeah. I doubt we'll ever win the war. But we may win a few battles and that still has some value I guess...
Title: Re: cannon and bullet
Post by: shadowmouse on May 22, 2015, 11:16:34 pm
Oh I didn't describe it very well because it does different things depending on the program, the two biggest ones I've done so far were as follows:
A made a graphical program (using SFML, thanks for giving me a good chance in my GCSE. Full marks in programming! :D ) that contained various separate functions that the exam board asked for and the brain class handled things like starting the program and doing titlescreen and menuscreen.

In my other one, in order to learn programming, I set myself the challenge of making a gameboy style game and it handled menus, saving, etc and in both, the brain class was used to store any variables that would need to be passed to lots of functions. I started doing it when I was getting functions with 20 -30 variable references passed to each function. This was when I thought encapsulation was stupid because it removes control and access and so everything was public and I used them in order to classify which variables were used for what so that I didn't have to do name mangling of my variables.
Title: Re: cannon and bullet
Post by: Jabberwocky on May 23, 2015, 04:42:09 pm
I've used singletons in several large production projects, and never run into a single problem with them.  Like any other code construct, it has to be properly designed, and properly used.  There are bad ways to use singletons.  There are also good ways.

The singleton class I use only has a static pointer to the singleton instance.  That pointer is allocated, assigned, and deleted in very precise fashion, on very precise lines of code.  There is no problem with the order of creation and destruction as has been discussed here.  This is a common singleton arrangement.

About the the criticism of global data.  In practice, this is an inconsequential critique.  Singletons should only be used for objects which exist for the lifetime of a game, from initialization to shutdown.  Whether that object lives in the stack, or is global has almost no practical consequence. 

Yes, a singleton can be accessed from anywhere, given you include the header and access functionality via the provided API.  This is exactly the convenience that Singletons provide.  If you used a non-singleton, this does not change where or when you will need to use that class' functionality.  Essentially, you end up doing the exact same thing, except the code to access that class might look a little different, and is often more cumbersome, and may require more layers of indirection.

I agree that, as much as possible, you should attempt to reduce coupling between systems.  But again, in practice, the systems in all but the simplest games will be interrelated to a large degree.  It is practically impossible to write code where your low level systems (graphics, sound, physics, etc) and higher-level gamesystems are not tightly coupled.  Most attempts to do so result in overly-complicated event-driven systems which don't change the interrelation, but just complicate it to the point that debugging and engineering is far more difficult. 

Most practical applications of threading I've seen in games involve easily split, repetitive tasks (e.g. processing updates on particle systems, or processing pathing data).  Using singletons does not make this any easier or any harder. 

Singletons are fine.  Just use a proper singleton class, and understand how and when to use them.
Title: Re: cannon and bullet
Post by: Jesper Juhl on May 27, 2015, 06:39:36 pm
Singletons are fine.  Just use a proper singleton class, and understand how and when to use them.
I guess we'll just have to agree to disagree.

If what you want is global access, then a global variable will do; you don't need a singleton for that.
If you only want a single instance of a class, then only create one; you don't need singletons for that.

I personally fail to see that singletons provide any real advantage and I'd personally much rather avoid them (and globals in general) and stick to having my objects constructed and destroyed in a deterministic way in deterministic scopes and just pass references or std::unique_ptr's/std::shared_ptr's where needed.

Of course you can use globals (and singletons) safely; it's just harder than just not using them. It's a tool and can have its uses. I just consider it a very sharp tool with very, very few real use cases, that is usually more trouble than gain. But, whatever floats your boat :)
Title: Re: cannon and bullet
Post by: StormWingDelta on May 29, 2015, 03:30:55 pm
Meanwhile while these guys are arguing about singletons.


Since the cannon fires the bullet it is a "has a" relationship meaning bullet is a field or just simply created by a method in the cannon class.

class Cannon
{
private:
     Bullet bullet
}

or

class Cannon
{
public:
Bullet fireBullet();
}
 

Just some ideas while these guys are arguing. :)
Title: Re: cannon and bullet
Post by: Jesper Juhl on May 29, 2015, 04:45:16 pm
Isn't that more-or-less what I already said as the first reply in this thread? ;)
Title: Re: cannon and bullet
Post by: StormWingDelta on May 30, 2015, 02:40:33 am
Isn't that more-or-less what I already said as the first reply in this thread? ;)

Yes but sometimes there are people that, well for lack of a better term need it simplified.  Sometimes less text is better, while other times making them figure it out is better.  Depends on the person. ???