This is no longer really relevant to beginners, so I'm going to close it (unless some other moderator wants to reopen it and move it to a more advanced forum).
Josh PetrieMember Since 11 Jun 2003
Offline Last Active Nov 20 2013 12:40 AM
- Group Moderators
- Active Posts 7,116
- Profile Views 13,053
- Submitted Links 0
- Member Title Moderator - For Beginners
- Age Age Unknown
- Birthday Birthday Unknown
Expert Community Member
Outstanding Forum Member
Blog post contributor
- Website URL http://joshpetrie.com
Posted by Josh Petrie on 25 July 2013 - 09:22 AM
Legacy code, and lots of it.
Why is there so much legacy code for C(98) and C++(pre tr1)? Why not VB6, Java 1.2, .NET 1.1 or other popular languages or platforms of past years?
In ~20 years, sure we will probably call things like SDL legacy and sure people will still be slating C++ against their new language of choice and yet C++ will still be going strong, SDL will still work and everyone would have long forgotten .NET, C# and XNA.
Washu was talking about the game development industry, predominantly the professional portion of it. There is almost no "legacy code" for VB6, Java, or .NET because it is almost never used for shipping professional games. Additionally, C++ is much older than any of those technologies.
You have a highly amusing view of the future.
Posted by Josh Petrie on 23 July 2013 - 09:23 AM
When I learned about Object Oriented Design for my first courses in Java, I sat down and read a book about Java for about 5 months. Then it finally clicked and all the theory I had read over time about how OOD works, suddenly made sense and I could pretty much utilize it all from the get got. It was the same concept I wanted to apply to learning Data Driven Design.
The thing is that despite a similarity in names, object-oriented design and data-driven design are different classes of concept entirely. The former is more structured an idea than the latter. I'd also challenge your assertions regarding your understanding of OO at that point in time, because many academic programs focus entirely on the wrong parts of OO and without using it extensively on real software, you don't really build up a true, "battle tested" understanding. One can acquire a passable understanding of a concept through books and other references, but until you really start using things in practice you have no idea how much you don't know you don't know.
I just really hate the notion of starting to code something and have no one by my side to consult with over it. Which is why I like getting taught by teachers rather than reading books or courses on the internet. If I make things wrong from the get-go and learn nothing I feel I've wasted my time.
You really need to disabuse yourself of this notion. Making mistakes is a critical part of learning and if you try to avoid it, you're only holding yourself back. Build games, and when you have questions or get stuck, you can ask people on the internet. Stop being afraid of doing it wrong. Everybody has, everybody will continue to do it wrong and make mistakes -- professional engineers who have been building games for ten years still make them happily.
You are holding yourself back by not trying to train yourself out of that pattern.
Posted by Josh Petrie on 23 July 2013 - 08:54 AM
As I said on GDSE, you are massively overcomplicating things. Data-driven design just means you keep your code and your data separate, and you allow the code to be directed by the data instead of the other way around. Simple things like loading configuration information from text files put you on the path to data-driven design.
Your problem appears to be that you are suffering from design paralysis because you're trying to take in the entire scope of everything that could be considered data-driven design at all once, including complete existing implementations, so you can rebuild it yourself. This is bound to result in frustration and failure. You need to start small, and build systems that you need for your games. Reading other people's code can be interesting, but often lacking in a lot of critical detail about the why of various decisions that can easily lead you astray.
Your dream goal is to have an engine on-par with AAA titles. That's great, but the way you're going to get there is not to explore a bunch of code other people have written that leverage data-driven techniques. You're going to get there by writing games. Don't worry about "making the engine very abstract so you can write many different games on it" to start with. You will evolve your code there eventually: for now, focus on smaller goals.
Pretty much the only piece of technology you need in place to start with is a way to actually load structured data from files. You can find great third-party libraries for parsing XML or JSON. For example, I use picojson often in C++. You may optionally want to have a serialization layer that uses the external library to turn data files into C++ structures, but for small projects I would not necessarily build that layer to start with. Wait until you have unburdened yourself of this design paralysis that plagues you right now.
Every time you build a new gameplay feature, take note of the inputs to that feature that control how it behave. Consider what is gating every conditional statement and while loop in that feature's code, and ask yourself "does it make sense that I'd want to tweak or change this?" If the answer is yes, consider how to put it into data.
Focus entirely on that concept for now, and finish a single simple game with it. Then, as you move on to another game, take stock of your existing code and see what is immediately re-usable, and what might be re-usable with some refactoring. Start to build that second game, and refactor the components you need as you need to increase their generality. Additionally, with your next project, pick a new aspect of technology to focus on. First you essentially focused on "loading data from files," so perhaps your second project would be the right time to start adding a more powerful serialization layer between the data and the code (so you're not just passing around XML node pointers or JSON objects into your feature code). Or, perhaps it's time to look into how you could implement a system that automatically reloaded data as it was changed.
By refining your code through projects with limited scope and concrete goals (a simple game), focusing each time on a small set of technology improvements, you will find yourself well on your way to having a reusable engine codebase. If you try to get there mainly by studying other people's code and one day sitting down and building the bulk of your final goal... you'll almost certainly fail.
Posted by Josh Petrie on 22 July 2013 - 01:21 PM
He doesn't seem to want your help or advice, so I'd suggest that you leave him alone to waste his own time if he so choses.
Posted by Josh Petrie on 20 June 2013 - 10:03 AM
I've got step-by-step instructions on how to create games on my website www.MarekKnows.com.
You'll want to start simple by first figuring out how to render an image on the screen. Then figure out how to move it, and then add some game logic. Start simple with something like Pong and work your way up.
Which seem to be behind some kind of complicated paywall / download credit system? This post reads too much like an advertisement for my taste. Please refrain from such content-free posts in the future.
Posted by Josh Petrie on 17 June 2013 - 09:17 AM
I would like to avoid using Windows Forms Designer; I would prefer to learn how to write it properly myself.
There's nothing "improper" about using the forms designer; it's there for a reason, and it can be an incredibly useful time-saving tool. There are places where it's not a great idea to use it, and that's fine (this probably isn't one of those places), but when you do avoid it you don't have to replicate the code it generates like you appear to have done. It's not usually necessary. In this case you've severely over-complicated things.
- Make a new C# Windows Forms application.
- Add a new UserControl.
- In that UserControl's constructor, subscribe to the KeyDown event: KeyDown += MyEventHandler (and implement MyEventHandler).
- In the default form created for you by the application template, drag and drop an instance of your user control from the toolbox to the form.
- Run your application, press a key.
In the default VS 2012 template, this should work fine. You don't need to muck about with your own form subclass, or with storing a static instance of that form within your user control (in fact that's a terrible idea). You're doing a fair bit of really weird / bad things in that code you've posted; I didn't go through all of it but that's probably the reason your events aren't firing correctly. You don't even appear to be calling Application.Run so your Windows event pump probably isn't running correctly.
Posted by Josh Petrie on 23 April 2013 - 08:55 AM
I think you would be making a poor career and life choice if you didn't finish school.
The answer to your question depends on what you define "successful" as. It is certainly possible to develop and release a game on your own time purely utilizing your own ideas and skills. However, the chance of that release becoming commercial success of the order required to serve as a replacement for full-time employment is smaller. It depends both on some measure of chance and some non-trivial measure of the skills you have in the realm of marketing and publicizing your game. If you go this route and the end result is a commercial flop, as is the case with most indie games, you'll find yourself in the potentially awkward position of having a subpar education relative your peers who you may now be competing in the job market against, simply because you need to do something to bring in sufficient sustained income to pay your rent.
There's no reason you should be gathering a team to help you on this game project at this point, you're only just learning the basic skills you'll need to put your game together. You can achieve a huge percentage of the work of making this game on your own, so bringing in other people will only complicate the process for you. Remove that complication and use the extra time it gives you to stay in school. Your future self will probably thank you.
Almost everybody who is technically inclined and/or intelligent has a tendency to develop the notion, at one point during their education, that they don't need school. That they're smart enough already. Most of the time those people are wrong, and the sooner they can be disabused of this notion, the better things will turn out for them in the long run. It sounds like you're going through that phase and you need to work through it -- it's unpleasant, I realize, but you should look for ways to work through the problems and boredom you are facing.
The paper that you linked, for example, is not impressive in any capacity. It's really little more than a large glossary of terms and the definitions you apply to those terms are in some cases wrong and in some cases clearly reflect your own youth and inexperience. It would make a very poor technical reference for anything.
If you're only learning C++ now you have a ways to go before you can really start building a game of any note -- especially since C++ is a very poor choice of first language (and if you already know another language, you could be using that instead to start building games now). Stay in school and work on putting together some games in your spare time. In a few years you'll actually have some games that might be a bit fun and are capable of demonstrating something more than basic core competencies in game development, and not only will that help you along your goal of making this non-player-centric game, but will put you well ahead of many hopeful game developers who will be finishing school and applying for jobs with no games or projects under their belt whatsoever beyond the stuff they were required to do for school.
Posted by Josh Petrie on 29 March 2013 - 08:56 AM
This isn't a worthwhile discussion -- "easier" is highly subjective, and there's more to it than the language itself (for example, the toolchains are a huge factor). Try both and see which you find more appealing.
Posted by Josh Petrie on 04 January 2013 - 04:34 PM
This is way off-topic for this forum now.
Posted by Josh Petrie on 09 December 2012 - 12:56 PM
Following that, learn about file IO and put your questions and answers in text files, then load them at runtime.
Posted by Josh Petrie on 15 November 2012 - 11:12 AM
Your sprite manager code has some game-specific constructs, such as a specific texture variable for the player and the ball. It also handles game-specific initialization and update logic, such as StartGame and the collision checks (even the fact that it handles collision at all is problematic).
At a high level, I would instead expect to see this:
- A type called "SpriteManager" should only understand how to manage a list of (generic) sprite objects and send them to the graphics card at render time. While these sprites may include position, width and height as data, that data is not necessarily what is used to perform collision. The idea that collision geometry and render geometry are distinct is a common practice and becomes very important with 3D games or even in 2D games when you have complicated shapes.
- You should have a distinct entity for representing collision geometry; perhaps a "CollisionShape" interface contains collision bounds information. These collision entities should be managed by a "CollisionWorld" or similar high-level interface that understands the relative positions of all collision entities and can raise events or invoke callbacks when any set of entities enters or leaves collision (or remains in collision across more than one frame, that can be useful as well).
Your top-level "game" class should be the one that contains all the game specific logic and types. The game class can maintain a set of logical game objects -- either using a single common class or, if their functionality differs wildly enough, many classes. Since we're already attempting to generalize quite a lot, I will leave further generalization of the game logic entities to you and, for the purposes of this example, say we have a Ball class and a Player class.
The game creates a ball instance, and asks the sprite manager to create a corresponding sprite. That sprite is stored in the ball object. Similarly, the game asks the collision world to construct a collision entity with the ball's dimensions and initial position in the world. A reference to that entity is also stored in the ball. Similarly for the player.
Now the game loop consists of, approximately: collecting player input, applying those inputs to the player object's collision entity (to move it), then asking the collision world to update. This will cause the collision world to fire any callbacks registered concerning inter-object collision -- the game would have installed a callback to handle ball-ball collision, ball-wall collision, and ball-player collision, possibly. In those callbacks, appropriate action can be taken by the game class -- perhaps to destroy one or both entities, or reflect the path of one to cause a "bounce" effect, et cetera.
Finally, the game looks at every game entity it knows about (balls, player, et cetera) and transfers the appropriate logical properties -- such as position, or damage state, or whatever -- to the object's renderable representation (the sprite in this case). Then your game asks the sprite manager to render all your frames.
With only this first level of generalization and refactoring (and there's much more you can do on top of this), you should have two systems -- the collision handling stuff and the sprite handling stuff -- that are entirely game-agnostic and can be reused and extended without having to couple them to the idea of a breakout (or any other) kind of game. It's only at the highest level of abstraction where your game-specific logic and means of tying these two systems together exist.
Posted by Josh Petrie on 10 November 2012 - 01:46 PM
You're right, people in the games industry can't design code, generally, but more importantly they don't. There is good reason for this. If you're writing software that gets men to the moon then:
- Get the best programmers available.
- Define a rock solid coding standard.
- Design every last operation detail of the code before writing a single line.
- Code review, code review, code review.
Unfortunately very often none of these rules apply in the games industry. The only time i've ever seen code designed to any kind of level in the industry was when a new boss of mine tried to enforce it but ended up having to drop it. There simply isn't time in the games industry because:
- You're usually working through shorter development iterations.
- Management and investors these days want to see progress on your project more frequently than they used to. (related to the above)
- Your title is out in a year and no time can be afford to be "wasted" on writing design documentation that, as soon as the game hits the shelf, is irrelevant.
I will say, however, that designing code and having good OOP has its merits. I'm not trying to say that noone in the world should be writing OOP, but in the games industry and to be honest, even more importantly for the hobbyist, don't waste all your time wondering how to add something to your perfectly architected system.
The more time you spend working out how the hell you're going to integrate physics into your engine the more time you're not spending integrating physics into your engine. You have to find a good balance between writing a codebase that will be productive to work on and also decently written and unfortunately for C++ and OOP allow you to code yourself into a corner too often.
I'm not disagreeing with you here, i understand the necessity of OOP in software engineering. I'm just not convinced the games industry is a suitable domain for it. I've been full circle with writing game engines in my personal time and my current one is my most productive. Gradually i'm migrating it over to plain C with a few C++ niceties like templates here and there.
While historically this is certainly true, I think our industry is maturing to the point where we can start to evolve out of the "cowboy coding" mentality that marked our formative years. Consider MMOs, for example -- you can't expect to build a successful MMO with poor engineering practices. You are building a service more than you are building a product you can ship and forget, a service you'll need to maintain and extend for a decade (or more, hopefully). Sure, MMOs as we know them today will eventually become passe, but some of their core elements, such as massively-connected (or "social," as the kids like to call it days) systems are probably going to embed themselves in the culture of our products for a long time. Even primarily single-player games are starting to integrate those kinds of features.
At ArenaNet, for example, we do a very good job of hitting three out of four of your bullet points. Our automated testing and test tools can be greatly improved (and we're working on it actively), but we take hiring extremely seriously, do up-front design of new systems and RFCs for changes to old ones, and have a very rigorous set of coding standards. We've developed these polices because we have to actively maintain two services -- Guild Wars 1 and now Guild Wars 2 -- for the foreseeable future and now, post-launch, we don't have the luxury of a five-year development cycle to get updates and patches out in to the live environment, so we've had to make sure these practices are followed reasonably during development so that they become habitual and we still employ them even when scrambling to patch an exploit or bug. If we don't, we're going to be building a house of cards for the next seven years -- the failure of which could basically cost the company its existence.
To your last point about writing more "C-like:" I don't think that's actually counter to the idea of writing code that espouses good (possibly OO) design principles. Such code tends to be simpler and consequently easier to read and maintain, and can still involve things like clear responsibility segregation, implementation hiding, et cetera. Much of our code at work is, for example, very C-like in its straightforwardness, and I do the same in many of my own hobby projects. Clever, complicated template metaprogramming hackery and overzealous design-pattern boilerplate implementations that adhere dogmatically to the Rules of Proper Design are, practically speaking, the domain of the academic, the "I wonder if I could..." masturbatory excursions that serve mostly to stretch the language and boost the ego of the author. Certainly, interesting innovations come from such endeavors, but increasingly I find must of them inappropriate for production code on any kind of scale.
Posted by Josh Petrie on 09 November 2012 - 11:09 PM
Regarding the bold bit -- no. You need to investigate the use of composition vs inheritance. Composition is a tool to allow for code re-use (not repeating yourself). Inheritance is a tool to allow for polymorphism. If you're looking for code re-use, you should default to composition, and only use inheritance where necessary.
The thing about this is that for every 'Shape child' I have to include the width, height, x, y variables separately. Isn't one of the advance of class hierarchy not having to repeat oneself.
Can every shape derivative be descrived with those 4 variables? Bregma hinted earlier that this probably isn't true -- e.g. polygons have a collection of vertices and edges, circles have a radius, squares have an edge-length... If you're making a polymorphic base class, you shouldn't include any variables that aren't going to be common to all derived classes.
If you do have variables that are common to all derived classes, you probably don't need to be using polymorphism either...
I would further stress that the "code reuse" advantage of inheritance is a plus, but should rarely be a major deciding factor in whether or not to employ inheritance. Just because two types might share a few member functions or member variables in their specific implementation doesn't mean one should immediately jump to the conclusion that you need a common base class to "save yourself the trouble of typing those members more than once." That's an abuse of the by-product of inheritance (which I have sadly seen in practice).
Posted by Josh Petrie on 09 November 2012 - 11:14 AM
In Game I might have a World class which also have Update() and Draw() methods. And in World there is a Player, but the Player class should be able to call a function in Graphics when a key is pressed. I can't do that in either Update() or Draw() since they only are passed one of Input and Graphics. In this case I find it really useful for one of them to global since I don't have to bother about this issue. I can see two options to solve this without the use of globals.
Maybe there are more options, what do you recommend doing?
- Change Game::Update() and World::Update() to take a Graphics* parameter.
- Add a Graphics* mGraphics member variable to each class that needs it, and set it with SetGraphics(Graphics* pGraphics) on initialization (what if I forget to set it?)
Ah, but like I noted before, I would argue here that the problem is with the design whereby "the Player class should be able to call a function in Graphics when a key is pressed." That's giving the player object responsibility over two very distinct systems (graphics and input), especially when the player appearance to be nothing more in this design than an entity within the logical world. You are now conflating, and thus coupling, your logical objects with your input and your rendering. With a bunch of singletons/globals this is less obvious, but when you remove them as you have suggested here, you discover those dependencies.
Ideally all three of those (logic, rendering, input processing) should be independent of each other. Communication between them should occur via the higher level container for each subsystem (in this case, the game itself, so perhaps in your "game" class).
The input system collects a bunch of keyboard events, or whatnot. Your game translates those (maybe via some kind of action mapper). Then it asks the world for the currently-controlled entity and uses the public interface of that entity to apply the actions. Once all that's done and the rest of the world goes through it's simulation step, the game collects all the visible/renderable entities and constructs (or updates) rendering descriptions for them, and feeds those rendering descriptions to the renderer object itself.
In this system:
- The "Player" class makes the most sense as the action mapper; all it has are a pointer to the currently-controlled world entity, and a bunch of methods to translate unmapped key codes into actions based on the entity state (for example, making the "V" key either draw or stow the entity's weapons, depending on the entity's current "are weapons drawn" state). The responsibility of the player is to change entity state.
- World logic, input logic and rendering are all independant, tied together at the topmost level by the game itself, which uses a Player object to translate between input and world systems.
- Similarly, the topmost game object also feeds input to the graphics by iterating all the active and renderable game entities and creating render descriptions (sprites, for example) using that data. The game determines whether to use animation sequence 0 (weapons stowed) or 1 (weapons drawn) for an entity based on that entity's state, but the graphics system only knows about and only has to see a bunch of sprites.