Jump to content

  • Log In with Google      Sign In   
  • Create Account


Cygon

Member Since 12 Oct 1999
Offline Last Active Aug 17 2014 06:06 AM

#5067582 Challenge #2: What tools can you not live without?

Posted by Cygon on 05 June 2013 - 04:31 AM

Blender. It was infamous for forcing people to memorize a ton of keyboard shortcuts before they could get any use out of it, but since the 2.50 redesign it has become very intuitive and its workflow allows me to work at insane speeds. Despite only being a 40 MiB download, it is a very complete tool: apart from modeling and skeletal animation, it can also do texture painting and sculpting (very similar to ZBrush).

 

PixPlant. There's an estimated ton of seamless texture generators out there. They all employ the same lazy technique: use a transparency gradient at the texture borders to blend over to the texture's other side. Voila, seamless. The makers of PixPlant actually tackled the problem: PixPlant allows you to select polygonal regions from a image to use as basis for a texture, applies perspective correction, tone correction and brightness correction and then puzzles these regions together so their features match up as good as possible.

 

Grindstone 2. Tracking time is a useful habit for a developer and having a place to write down tasks is a boon. Grindstone was a time tracker that aimed for simplicity. A task list, a play and a stop button. Things you used less often, like reporting, client/project overviews, invoices, etc. were tucked away and out of view. I'm talking in the past tense because, after a particularly silly PC World review that wanted more funny colors, they made a version 3 with a cluttered UI and pointless gimmicks like achievements (yes, really). Thus I recommend version 2, but not version 3.

 

Jasc Paint Shop Pro 9. It's a very fast and slim bitmap editor with tons of effects and color adjustments. It also supports layers and alpha channel editing. They were acquired by Corel which promptly added tons of bloat and DRM to it, so if GIMP and Paint.net aren't your cup of tea, I recommend the old Jasc Paint Shop Pro. It causes Windows 7 to temporarily disable the Aero shell, but works really well on Windows 8 again.

 

UML Sculptor. The original project hasn't received an update since 2002, but I've fixed some bugs and added .svg export to it. UML Sculptor is a UML class diagram editor that consists of a single executable. It's like drawing on a piece of paper - add a class, double-click under "attributes" or "methods," type you method name. No combo boxes, no method entry dialogs, no round-trip engineering. Ideal for brainstorming, communicating ideas and documentation.




#4972108 Game: Appstates and management

Posted by Cygon on 22 August 2012 - 01:45 AM

It's usually referred to as a "game state manager" - that at least will yield you several results on Google. Also see the related "state pattern".

I was in a similar situation with my last game but ultimately settled on writing my own when each and every example either tightly coupled the game states to a specific engine or library, or decided to hard-code it for one purpose.

If you can use it, I have published my code together with a small article showing how to avoid common design pitfalls here: Game State Management.


#4966824 is C# an alternative to C++?

Posted by Cygon on 06 August 2012 - 03:29 PM

Weird post. Trying to let off some steam after a failed learning attempt?

I found it to be one of the nicest and most complete environments I ever worked in. It's incredibly cool to be able to run the same binaries on Windows and Linux (and Android and iPhone). Porting has always been a big effort before. Mono also has the smallest overhead of all "managed" languages (like Python, Java, Ruby) and can bundle the Mono runtime with an application so users get a single executable and don't have to have Mono installed (between 1 and 2.5 MB - which is incredible given the extensive .NET BCL).

EDIT: Regarding the "hardly used language" bit - check the tag frequencies on StackOverflow, for example. C# is 3 times as popular as C++ there. It has almost driven C++ extinct in the business world. And yet is still mostly under the radar for Linux users. How popular it appears depends very much on which circles you frequent.


#4963564 uses undefined class? But pointer is ok?

Posted by Cygon on 27 July 2012 - 02:25 AM

You can use a "forward declaration" in C++ that only tells the compiler that there is a class or structure with a certain name, but nothing more:

class town; // forward declaration
town *plainPointer;
std::unique_ptr<town> wrappedPointer;

This pointer can be passed on, but since the compiler doesn't know anything about it, you cannot call methods on it or safely delete it.

Your error message sounds exactly like that is your problem, but you haven't told us enough to say why this is happening in your case. If I should make a guess, perhaps you are including town.h from another header and accidentally set up a circular header dependency, which then causes this due to the include guards being triggered in a certain way:

#ifndef OTHER_H
#define OTHER_H

#include "town.h"

class town;

class other {
  town the_town;
};

#endif // OTHER_H
#ifndef TOWN_H
#define TOWN_H

#include "other.h"

class town {
  other *owner;
};

#endif // TOWN_H

In this case, when town.h is compiled, TOWN_H gets defined. Then other.h gets included. When other.h tries to include town.h back, TOWN_H is already defined, thus other.h gets processed without the contents of town.h, leaving only the forward declaration for the compiler.

EDIT: Is the code snippet feature currently broken? EDIT2: Tried again, works.


#4960396 One-Step vs Two-Step Initialization (C++)

Posted by Cygon on 18 July 2012 - 03:16 AM

@Matias Goldberg: I got that. I didn't want to imply you recommended copy&paste programming. When you wrote "...rather than having to refactor everything or resort to copy-pasting the constructor into a reinit() function, then debug why reinit is failing (because you pasted more code than you should, or forgot to copy something).", in my opinion reinit() is a) just another form of two-stage initialization and b) can avoid code duplication just the same (it's not like reinit() would somehow force it).

I would still strongly prefer one-stage initialization in all 4 cases you listed. But instead of just criticizing your design, let me explain how I would have done it and you can criticize mine Posted Image)

Object reloading for memory & performance: I have a logical game object which maintains the persistent state (eg. class ScarySpider with int health, Item loot, int xp). Add AI, physics etc. via composition. This thing gets loaded and saved with a level and in savegames. With a client/server model, the server would only work with this logical game object. To actually render it, there is a class ScarySpiderPresenter which creates and maintains the visual and audible representation of the logical game object in the game's scene graph. If I wanted to reclaim memory this way, I'd destroy the ScarySpiderPresenter but leave the ScarySpider.

Reloading for in-place editing: Kill ScarySpiderPresenter, create ScarySpiderEditorPresenter. The latter could derive from the former or both could derive from a common base class as appropriate if there is shared functionality. This presenter could draw bounding boxes, overlay the AI's current patrol path / attack target or display scale and rotate widgets or whatever you like. Normal gameplay is not burdened with dragging the editor-specific state variables along as dead code.

Level reloading: Either be very clever and mutate the active world's state into the state loaded from the saved game / level (this is how I understood your approach) which will neatly cause the presenter hierarchy to create/destroy presenters as needed, all without requiring the save/load code to get clogged dealing out references to graphics devices, input managers and audio managers to the newly created objects. Or alternatively go ahead and kill the world with its presenters, then recreate it, taking into account that long loading times primarily result from needlessly reloading resources from disk - which can be solved by a resource manager with a LRU list and a memory budget.

So in short, whenever two-stage initialization is used, there are actually two classes being glued together. Yes, design gets more complicated as a project's scope grows and the effort to change late in the process becomes ever larger. All the more reason to pay attention to it, especially if one is not just coding Tetris of Pac Man!


#4959943 One-Step vs Two-Step Initialization (C++)

Posted by Cygon on 17 July 2012 - 03:55 AM

But it may be posible that some of these objects must, for some reason, stay persistent throughout levels or even game sessions. So, you can't delete them and create new ones, but you'll probably need to reinitialize most of it's variables to a default value.
For these cases a two-step approach is much better suited, where you just call init( bool firstTime ) rather than having to refactor everything or resort to copy-pasting the constructor into a reinit() function, then debug why reinit is failing (because you pasted more code than you should, or forgot to copy something).
I also use this two-step approach when suitable.


And that is, in my opinion, where your design went bad. It only seems that the two-step approach is "much better suited" because earlier on, you failed to separate those parts of your game object that survive a map change from those that are map specific.

By knitting them both into the same class, you created a weird amalgamation which will cause raised eyebrows in many situations: if you want to save the game's state, you would have to carfully check what is permanent (= you save it) and what is level-specific (= don't save it, but pull it from somewhere after the object was loaded). If the map is unloaded, only a subset of the methods of those game objects may be used (= be careful to document which methods you may use when displaying eg. player stats in the menu without a loaded map).

Whether you implement such two-stage initialization with Init()/Shutdown() or Reinit() are just details - it's both two-stage initialization. Code duplication would be avoidable in both cases.


#4959730 MVC

Posted by Cygon on 16 July 2012 - 02:39 PM

It's an architectural modal mostly used for web frameworks. Typically like this:
  • You've got the model which represents your state / your data as objects. For a blog, your model might consist of a repository of post objects which contain text and comment objects.
  • A controller responds to requests from the outside. For example, accessing the url http://example.com/article/show/123 might load the ArticleController and call its Show() method with the parameter 123 in modern MVC frameworks. It will then look up the blog post in the model, create an appropriate view and feed it the data it needs (so the view isn't coupled to the model)
  • Each view has a well defined set of inputs (to be filled by the controller) and is responsible for presenting these inputs (for example, a blog post and associated comments) to the user (in this case, by generating HTML code).

For GUI applications on the desktop (especially WPF and anything XAML-based), MVVM (or MVP) is a more appropriate pattern
  • The model represents the data, either by interfaces with a data store or holding it directly, just like in MVC.
  • The viewmodel (or presenter) refines the data to a format on which data binding can be applied. Data binding means that instead of letting the view create a listbox and filling it with all the items it should display, you tell the listbox to display the contents of a collection and describe how items are to be represented visually. The viewmodel also provides commands, for the view to invoke, typically via methods like Accept(), AddItem(), DeleteSelection(), etc.
  • The view binds to the data exposed by the viewmodel.

I've seen some attempts at applying MVC to games. You'll have to adapt it a bit, but the following would be entirely possible, for example:
  • The game's model contains the state of the world. It does not hold any references to anything graphics-related and could run the game in a console application. If something in the world changes (eg. a new building it added), it triggers an event (eg. using a signal/slot system)
  • The game's presenter observes the model and creates/destroys entities in the game's scene graph and updates existing entities for according to what happens in the model. The presenter could be reused in the main game and the editor.
  • The game's controller makes use of the presenter to render the world and adds its own stuff on top. If the controller was a map editor, it might add toolbars and object picking / moving overlays. If the controller was the game, it might add command panels, a health display or similar things on top of the rest.



#4959707 One-Step vs Two-Step Initialization (C++)

Posted by Cygon on 16 July 2012 - 01:49 PM

All my classes are initialized in their constructors and destroyed through their destructors.

I've worked on countless large-scale projects and claiming that some objects "need" two-stage construction because they are too complex just means you're putting too much stuff in a single class. One class, one purpose. Using methods like Init() and Shutdown() is just sloppy style and could be avoided by properly designing your object model. Yet for some reason some C++ programmers appear to be scared of adding classes - usually with excuses like overhead, performance, binary size and whatnot.

C++ classes are designed to be usable without overhead. You can declare a struct with some methods and an std::uint16_t in it and it will have a size of 2 bytes. If you stack-allocate it's the same as if the code was implemented in its owner class. That's why there's really no point to writing silly classes like CGraphics with InitWindow(), InitD3D() and stuff like that.


Same goes for exceptions. I don't do error handling without exceptions. That includes Windows, the Xbox 360, Android (Crystax NDK) and WinRT (Win8+tablets+phone).

There aren't only those cases where someone mistyped an asset filename (and even then exceptions would be the appropriate choice: the OpenFile() method can't resolve the error, so it goes up the call stack - the LoadImage() method can't resolve it either, so up it goes again - the ReadAssets() method finally could catch it, log the error and use a pink placeholder asset). Back to the paragraph's opening line, there are tons of other cases where errors can occur and you can't do a thing. Failed to initialize Direct3D. No compatible graphics adapter. Unsupported pixel format. Swap chain resize failed. And of course all those little API calls that usually work, but where due diligence requires us to check that they really did their job.

The point many C++ programmers don't get is that exceptions aren't fatal, they merely indicate that the current scope can't reasonably deal with the error. Yes, there's the concept of exception safety, forcing you to employ RAII. If you ignore it, funny things may happen. Without exceptions, there's the risk of forgetting to check result codes, forcing you to make your code unreadable by littering it with error checks. If you ignore it, funny things may happen, too. Given the decision between tedious result code checking with unreadable code and equally tedious RAII programming with nice code, guess what I'll pick.



#4954286 Realtime Main Loop Structure

Posted by Cygon on 30 June 2012 - 05:44 AM

As others already said, the key repeats are few and far between for a computer -- they aren't generated by PeekMessage(), but by a microchip inside your keyboard or an internal timer in Windows/Linux.

Let's make the following assumption: Your game runs really slow, 0.1 fps (10 seconds from one frame to the next) and your keyboard is set really fast, like 30 repeats/second:
- Whilst the game is updating and drawing, 300 WM_KEYDOWN messages will enter the queue.
- Then the game processes all 300 messages. This takes somewhere around 0 milliseconds.
- Now the message queue is empty again, PeekMessage() returns FALSE and the game works on the next frame for 10 seconds

To actually stop your game from drawing and updating, someone would have to send hundreds of thousands of messages to your window, at least as fast as you can process them.


#4952261 Planning - What do you use?

Posted by Cygon on 24 June 2012 - 02:51 AM

I've been designing my classes in my head for about 10 years and only then started using UML. Those years before certainly weren't for naught, since I acquired to skill to explore designs in my head (trying to describe the process is a bit weird... it's like arranging the classes in 3D, but they have no geometric shape, I just know where they are) :)

But there's a limit to how big a system I can keep in my head, so that's what I now use UML for. I think about small islands of objects while keeping in mind what the rest of the system requires from them. I can always look at the whole system in my UML diagrams. They're also cool to communicate ideas and concepts to other people (though it takes some getting used to if those other people have worked primarily with pure code before -- it's like a foreign language, at first you concentrate on just getting the meaning before it becomes intuitive and you /see/ the meaning while you can think about the idea the whole diagram communicates).

I use UML Sculptor as well (see URL above).

I tried several other tools (including high profile ones), but they all had such a cumbersome workflow that they would be more suitable as post-mortem documentation tools and not for exploring designs.


#4950531 Structure of classes in good Game Engine?

Posted by Cygon on 19 June 2012 - 04:28 AM

My opinion:
  • Using globals is always wrong. They create a mess with initialization ordering, threading and dependencies.
  • A free function would open the door for dozens of globals. Enable/Disable logging to OutputDebugString() - you need a global flag. Write log to a file? You need another global flag and a global variable storing the file handle.
  • Singletons, global variables in disguise, rob you of all flexibility (like logging networking related stuff in file 1 and graphics related stuff in file 2) and gets in the way of unit testing.
  • Passing some semi-global application class around is just hugely increasing dependencies since now you don't know which objects a class will look up through the application class (the service locator anti-pattern).

The way you're doing it (constructor injection) is quite alright, though I agree that having to pass your logger everywhere you want to create an instance of class X tends to have a negative impact on usability and adds complexity to the interface.

Some other options:
  • Equip your classes with a SetLogger() method. By default, the logger is NULL, therefore no logging is performed. If you want to log something, you simply assign the logger to the class post construction.
  • Do not add logging to your classes directly, wrap them in a logging wrapper (eg. a LoggedRenderer around your Renderer). Obviously can only log calls and results and with some effort exceptions leaving the renderer.
  • Add a Log event (as in signals/slots) to your class. This is just another variant of the SetLogger() idea, of course.
  • Forfeit logging altogether. I've done this in my code. I'm going all-out with assertions for pedantically checking internal states and exceptions for any usage error. Since the point of logging is to help you find the cause of errors quickly, by not letting any inconsistency, bad return code or missing capability slip under the carpet you remove the need for logging.



#4947414 Visual Studio 2012 Express won't support Win32 Projects

Posted by Cygon on 08 June 2012 - 11:01 AM

We won! Microsoft has given in!

Today, the Visual Studio blog announced that after disabling desktop application support in the Express editions since Visual Studio 11 Beta, the final Visual Studio 2012 Express release will be supporting desktop applications once again!

To add a little bit to the confusion, there will now be two Express editions. One will be Visual Studio 2012 Express, just as we know it today, the other will have the long-winded name Visual Studio 2012 Express for Windows Desktop.


#4946344 Generating all possible combinations

Posted by Cygon on 05 June 2012 - 02:52 AM

Oh my, an entire thread of code samples for a problem that's already solved by the C++ standard library :)

[source lang="cpp"]#include &lt;vector&gt;#include &lt;algorithm&gt;#include &lt;iostream&gt;#include &lt;string&gt;int main() { using namespace std; std::string wordOrNumber; cout &lt;&lt; "Enter a word or a number: "; cin &gt;&gt; wordOrNumber; cout &lt;&lt; "Listing all permutations: " &lt;&lt; endl; do { cout &lt;&lt; wordOrNumber &lt;&lt; endl; } while(next_permutation(wordOrNumber.begin(), wordOrNumber.end()));}[/source]

Example:
Enter a word or a number: 123
Listing all permutations:
123
132
213
231
312
321



#4946328 Main game loop design

Posted by Cygon on 05 June 2012 - 01:45 AM

I _really_ _strongly_ _passionately_ hate event systems. One day I'm going to write an entire blog post dedicated as to why they're terrible in my opinion :)

I'm using fixed time steps as well for most of my works. In multiplayer, it's a must to achieve identical results on all system and in single player games, it makes a lot of situations more controllable (like physics libraries which, despite all the clever math, tend to produce vastly different outcomes depending on the amount by which simulation time is advanced).

To keep my main loop simple, I'm using a small class that encapsulates most of the math involved for the time stepping:
[source lang="cpp"]void MyGame::RunGameLoop() { SteppedTimer timer(Clock::GetSystemDefault()); timer.SetStepFrequency(60); while(!this->endRequested) { // Update the state of the game world GameTime timeStep; while(timer.TryAdvance(timeStep)) { Update(timeStep); } // Draw the game world GameTime frameTime = timer.GetFrameTimeAndReset(); Draw(frameTime); }}[/source]

I only moved the calculations for the delta time and time steps into a class so I can use more expressive names inside my main loop. Still, if you're curious, I posted the code for the SteppedTimer class in one of my blog posts: Perfectly Accurate Game Timing.


#4946321 Multi-purpose library vs Many Libraries

Posted by Cygon on 05 June 2012 - 01:02 AM

But completely isolating the pieces of Boost you want from the rest is not an easy thing either.

Most of the time you need Boost.Config, Boost.MPL, Boost.Spirit right away plus a dozen random headers from different Boost libraries (and this is where the fun starts - can you only include those headers oder do you then include the whole library).

I remember writing a shell script that called the compiler, parsed its output for error messages about missing headers and then copied the headers in place -- all just to obtain a minimal Boost subset for my project.




PARTNERS