Jump to content

  • Log In with Google      Sign In   
  • Create Account


Member Since 11 Mar 2000
Offline Last Active Dec 22 2015 02:19 PM

#5262930 MyClass myClass VS myClass = new MyClass()

Posted by on 20 November 2015 - 04:05 PM

The stack requires that the lifetime of your object be known and fixed at compile-time. Indeed, the compiler depends on it to generate the proper stack framing code. The code you have now can't satisfy those conditions because it must wait some indeterminable amount of time before the window is created, thus requiring late-binding and heap allocation.


However let's say you re-arrange your code like this:

void MainLoop()
    while(!window->OpenGLContext->Inited()) { /* handle exit */ }

    // Guaranteed OpenGL context is initialize
    SpriteBatcher batcher(window->OpenGLContext);
    bool run = true;
        /* main loop stuff */

Your code waits until the OpenGL context is initialized before creating the sprite batcher, which can be created on the stack because it's lifetime can be entirely code-driven.

#5262914 Random errors in Release builds

Posted by on 20 November 2015 - 01:32 PM

I've often found uninitialized variables and/or memory to be the culprit behind these kinds of issues, where things mysteriously break in one build or once deployed, *especially* in release builds.


Start with remote debugging when the issue presents, and then lots and lots of logging!

#5262802 Integrating a scripting language

Posted by on 19 November 2015 - 05:48 PM

Start by thinking of the scripting VM as its own independent domain, with absolutely no concept of shared state or direct access with your native code. We could even assume it's in a separate process entirely.


Notice how this resembles a client/server architecture. As such, you could use RPC mechanisms to allow them to communicate. Notice how all the mechanics and details of the script/native interaction are now the responsibility of a dedicated communication layer, as opposed to requiring the script code or native code to understand those details at every turn. Shared ownership isn't even a thing.


Next, let's move the script VM to the same domain as the native code and allow them direct access to each other. You no longer need to marshall and communicate a copy of the data across a domain boundary and have it updated remotely; you just set the new value directly and raise a 'changed' event. The state update can be accomplished via injection -- the script owns the data it's going to consume, but passes a reference to native code so it can be populated as necessary. Before the script goes away, it passes a null reference to the native code indicating it's no longer valid. Since we've designed the architecture so that the scope of the script's ownership always encapsulates the scope of the native code's ownership (or vice versa) of a particular piece of state, we don't run into any of the typical shared ownership issues and we could use a weak reference if the scripting language supports it; but at that point it's an implementation detail.


However the cost of such an approach is requiring the native code to have privileged knowledge of the script's data layout, since you're no longer using the same neutral data representations which exist as part of a communication protocol. You trade run-time efficiency, for additional maintenance overhead. However I've often found that to be an acceptable trade-off , since the script-side interaction with an RPC layer can often be a problematic if lots of short-lived temporary objects end up being created often.

#5262767 Multiple server architecture

Posted by on 19 November 2015 - 12:58 PM

Now, is it feasible to have the game servers connect to the chat server? So the client could send a message to the game server with chat information and the game server sends that along to the chat server rather than having the client handle the separate game/chat connections.

There's nothing wrong with having multiple connections from the client to various back-end components. In this case, you're going to have two separate connections, one for the game server, and another for the chat server. When a game server starts up, it sends a request to the chat server to create a new channel (a privileged operation not available to clients). When clients join the game server, they're told to join the previously created channel. Likewise, when a client leaves the game server, they're kicked from the chat channel. When the game server shuts down, it destroys the channel and all the remaining clients get kicked.


You don't have to restrict chat to game servers, either. You can have a chat channel for players looking for games from the "main" server, one for each guild (if your game supports that), one for people who need technical support, etc. Once you decouple chat functionality from game functionality, the possibilities expand tremendously.

#5262625 Discombobulated input callbacks

Posted by on 18 November 2015 - 02:24 PM

I don't know.  What happens when the camera dies?  How does the dispatcher know to unregister that dangly pointer?  Seems like this just moves that responsibility to the camera object, which then needs to be reimplemented for every game object that registers functions to the dispatcher.  Unless I am misunderstanding.


My example was a little hasty, you can't actually unregister the function if you use that exact code. The approach would look more like:

class Camera
   Camera() : m_callback(std::bind(Camera::moveLeft, this))
      dispatcher.register(&m_callback, event::CAM_MOVE_LEFT);

      dispatcher.unregister(&m_callback, event::CAM_MOVE_LEFT);

   void moveLeft() { ... }

   std::function<void()> m_callback;

You'll get a C4355 warning, which is safe to ignore in this particular instance (and there are ways around it)... but none of it is very pretty. Note the aforementioned level of indirection.


I personally use fast delegates whenever I'm dealing with delegates in C++. They just make this kind of code a lot easier to work with than std::function.



How do you handle storing the objects (like the camera) in a container (std::vector or similar).  Doesn't that require a copy?





What is the alternative? 
Are you saying that the entire Input->MapToActionsWithAContext->ActOnThoseActions model doesn't work well?
Or are you saying that the final step of resolving the action via callback does not work well?
How else does the game object act upon the action event?


I've never had any issue using delegates to handle input actions. They're just the final step where you associate the triggering of an action to some code you want to execute. The input contexts are what provide the layer of indirection needed to implement your interaction model.

#5262444 Coding "cheat codes" into games

Posted by on 17 November 2015 - 12:45 PM

I can't remember the last time we added a "cheat code" that wasn't purely to aide in development somehow (and thus disabled in public builds), or to show off specific features for demos and trade shows (again, only enabled for those demo builds). Modern games have enough bugs as it is without also having to test all the myriad of ways cheats can be applied at any point in the game.


Plus, as frob mentioned, making sure that "cheat" state stays sandboxed and doesn't pollute other areas of the game like leaderboards, achievements, stats, rankings, etc., can be a monumental undertaking in and of itself.

#5262332 Integrating a scripting language

Posted by on 16 November 2015 - 05:23 PM

One issue (?) that exists among all the scripting languages I've looked at is memory management. At the moment all of my C++ code is either using unique or weak ownership (via my own UniquePtr and WeakPtr classes). Neither scripting language really has any concept of that, and while I suppose I could dance around the issue by simply not exposing anything that requires "ownership" to the scripting layer, that could get very tricky. While it wouldn't be much of an issue creating objects on the scripting side, sharing objects created in C++ would be difficult.

I wouldn't allow any sort of shared script/native representations of objects in the first place, which allows you to avoid these sorts of cross-domain ownership issues. At which point it doesn't matter how they each handle object ownership/lifetime, so long as you can properly marshall between the two.

#5261639 Consistent handling of hotkeys in other languages

Posted by on 11 November 2015 - 12:38 PM

Virtual keys have the same physical position in every keyboard layout.


I was initially under this impression as well, but unfortunately it doesn't appear to be the case. It's easy enough to demonstrate, just breakpoint your WM_KEYDOWN handler and press a key -- such as 'Q' -- with an 'English - US' keyboard set. The virtual key code is 0x51, as you'd expect. Now use the language bar to switch the keyboard to something like 'Turkish (Turkey) - Turkish F'. The same 'Q' key now has a virtual key code of 0x46, which is what you'd expect from the 'F' key. The OEM codes can get especially jumbled.

#5261448 Consistent handling of hotkeys in other languages

Posted by on 10 November 2015 - 06:16 PM

I recently came across an interesting issue with how we handle hotkey mapping under international keyboard layouts, as was wondering if others have encountered a similar issue and how they dealt with it.


Right now we use some common hotkey groupings as defaults in our game (WASD, QWERTY, etc.). However we noticed that if the user changes their active keyboard layout to something else, like Turkish, these defaults no longer work that well because we map from virtual keys, and these virtual keys are only physically grouped together on a handful of keyboard layouts (U.S. in our case).


The user can always remap their keys, but I'm hoping to come up with some sort of solution to automatically map the default virtual key assignments from the assumed U.S. keyboard layout to the active keyboard layout, at the very least to preserve the usefulness of the defaults for as many players as possible. However the more I look into it, the less feasible it seems.


Does anyone have any experience with this issue? Did you find a solution/workaround, or did you just accept that your default keyboard bindings might suck for some international users and have them re-bind their keys?

#5260564 Data organization with graphics front-end

Posted by on 04 November 2015 - 07:22 PM

It's unlikely that the simulation and the renderer are going to use the same representation of the data anyway, so you'll need two copies regardless. The renderer might have two copies of its data as well if it wants to perform interpolation while the simulation build the next frame. It then becomes a question of how and when you synchronize the simulation state with the renderer state. This is where you can utilize dirty flags and other techniques to only synchronize state that changed.

#5258023 Confusion with smart pointers

Posted by on 19 October 2015 - 06:26 PM

So, I read that you cannot have two std::unique_ptr point to same object.


Technically you can:

#include <memory>

int main()
   int* foo = new int;
   std::unique_ptr<int> fooPtr1(foo);
   std::unique_ptr<int> fooPtr2(foo); // Double-delete bug!

So always be careful (and consistent!) with how you mix and match your smart pointers with your regular pointers!

#5257585 Game Engine Creation: What are the biggest challenges faced?

Posted by on 16 October 2015 - 05:53 PM

What are the biggest issues/challenges/difficulties faced when creating a game engine?


Getting it to a point where you can actually create a game using it.


You're usually not going to have a lot to show for a game engine other than a handful of tech demos, especially during the first few months (years?!) of development, and that necessitates a lot of self-motivation. And unless you have some concrete goals in mind and a realistic scope for your engine, i.e. what kind of game(s) it's designed to be used on, features you want it to support, etc., development can likely linger on aimlessly because you never consider it "ready". That's why it's often recommended that one focuses on developing a few games first, and having the engine fall out of those based on commonly used functionality.

#5257374 Optimizing data synchronization between game modules. A design issue.

Posted by on 15 October 2015 - 12:40 PM

You could try a singular synchronization point within your game loop where all actors have their state sync'd, instead of having each actor be responsible for syncing its own state whenever it's ready. Something like this:

   // run physics frame

   // render until physics frame is done
   } while (!physicsThread.done());

   // sync physics state to render state

Whenever new state from frame N is synced to a renderable, you cache off the old state from frame N-1, and interpolate between the two during the next frame. In this way the renderer doesn't need to do any prediction, since it already has two known states, but you still have the option to if physics falls behind.


As for where the data lives, I think you're doing fine with each component storing the relevant data used by its respective system. The real issue is who is accessing that data and when. If you add more systems that run on separate threads, you'll have to start double-buffering shared state to eliminate contention.

#5257227 Why didn't somebody tell me?

Posted by on 14 October 2015 - 01:28 PM

1) If you hold down Alt when selecting text, it will allow you to select text as a block (same as marking in a command window). Very handy for adding tabs to many lines at once, or other batch formatting tasks!


2) You can hold Ctrl while using the arrow keys to move the cursor by word through text, instead of by character! Combine with Shift for selection.


3) The command window in Visual Studio can quickly open files by name using the "of" command, and it has auto-complete! Useful for when you don't have add-ons with similar features.


4) A whole slew of handy Visual Studio shortcuts.

#5256956 Tips and Parables From the Gamedev Members

Posted by on 12 October 2015 - 08:32 PM

Here's some advice based on my experience throughout the years in no particular order:


1) Perfect is the enemy of good. Get it done and working first, then iterate later if there's time and/or necessity. Keep in mind that performance isn't always the first priority.

2) As a corollary to (1), try to come up with more than one solution to a given problem, in case one turns out to be a dead-end or you unexpectedly have to change course. I personally try to have at least three; one that represents the "ideal" solution I'd use if I had infinite time and resources, one that represents the fastest possible solution to get things functional if I was crunching and had to be finished yesterday, and one that's some trade-off between the two. The final solution is usually somewhere between two of the three, and you've established multiple possible starting points for future iteration.

2) Always keep your customers' needs in mind. That doesn't just mean end-users; it includes everyone on your team, even your future self. If that means physically collocating yourself so you can watch a content creator work for a day or two, do it.

3) Demand full specs for every feature. Get clarification for any circumstances or edge cases not covered. Have this information readily accessible to everyone on the team. Miscommunication can be very expensive. Ideally, you should make sure that the information is in a format that makes verification as easy as possible for the testing team (although an addendum with testing procedures also works just fine). Go so far as to follow this testing procedure yourself so you can catch any obvious and low-hanging fruit and eliminate the overhead of sending it down the line.

4) Everything should be owned by someone. Whether that be a feature, a process, a document, a system, a tool, the creative vision of the entire game, etc., there must be someone who has a vision of where it's going and has the authority to make decisions. This sometimes takes the form of one person per discipline, i.e. one engineer, one designer, and one artist, each making decisions on behalf of their respective department. Design by committee can and will grind development to a halt. Vision and decisiveness keeps things moving smoothly.

5) Know where your development time is going. You may have a very robust process in place for scheduling tasks and determining time estimates, but if you don't track how much time it takes to fix bugs, for instance (or allow non-critical bugs to become known issues and backlogged for later once you've spent too much time on them), then you really don't have a full picture of your time costs and it's easier to fall behind.

6) Track everything (partly a corollary to (5)). Get you and your team some decent project tracking software (at work we use JIRA) and don't be afraid to use it. You'll have quantitative measurements of your team's progress and you'll always know who's working on what. Plus, if someone has some extra time between builds or reaches a stopping point, they might find an issue they can knock out a fix for real quick.

7) Don't take unnecessary shortcuts based on guesstimated time savings. Make an honest assessment of how much longer the correct approach will take versus the fast approach, including future maintenance effort and bug risk. Ask yourself if that extra few hours is really worth it. More often than not, it isn't, and the extra time to do something right saves you and your team lots of headaches down the line.

8) Be wary of data that begins to feel too much like code, unless it's actually supposed to be code (like scripts). You tend to see this kind of data with large game-logic systems that "do all the things!", where multiple games over the years have added their one-off features to the system but tried to make them general-purpose under the assumption that it would be used again, but often never is. At some point, the system grows so large and complex that the behavior of the system is defined more by the data than the code, and it becomes a nightmare to work with for everyone involved.

9) Not everything has to be built to last forever. Acknowledge that a lot of game code is throwaway and can't/shouldn't be used again for another project. Over time, your experience will tell you which code and systems these are. You can always go back and get old code if you realize a need for it in the future.

10) Be as consistent as possible. Don't use different solutions to multiple similar problems. Even if you do something wrong, and you repeat that error in multiple places, it's still easier to fix a consistent mistake than an inconsistent one. Human beings are built to recognize patterns, after all, no matter what they are.