munificent / game-programming-patterns Goto Github PK
View Code? Open in Web Editor NEWSource repo for the book
Home Page: http://gameprogrammingpatterns.com/
License: Other
Source repo for the book
Home Page: http://gameprogrammingpatterns.com/
License: Other
From poik on reddit:
"In my tests while writing this chapter, there was no noticeable difference between using an enum or a flyweight. Flyweights were actually noticeably faster."
So was there a noticeable difference or not? Still can't tell.
s/whirlwhind/whirlwind/
This is a rare hat trick in architecture: your code is both more maintainable and faster.
A hat trick refers to a group of three or more wins.
On this page http://gameprogrammingpatterns.com/type-object.html
I am seeing this in a code/monospace block:
… lots more subclasses…
Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0
Referring to the 2nd graphic in the "Commands" pattern.
Expected Image:
X tied to Button_X
B tied to Button_B
Actual Image:
X tied to Button_B
B tied to Button_X
In the description of type objects, the inheritance used is implemented by holding a pointer to the base and checking, at every call, whether the value is overridden or not. Later, it is mentioned that deep inheritance could lead to a performance issue.
There is a simple way of solving this, which I think should at least be mentioned.
Since all types are initialized from data and never changed after initialization, we might as well skip the parent_ member and initialize the derived Breed by copying the parent values, except for the overridden parts. This means a very small additional overhead at initialization (the same checks which are currently done in the get methods), which will definitely be dwarfed by reading the data from disk. This initialization completely replaces all later checks for data overriding, and even reduces the object size of Behavior instances.
This means we can remove all recursion from the Breed class, making the getters constant-time functions consisting of a single return call. Please note that, since the parent object will already have been constructed this way, our Breed type will not need any recursion in the constructor, either.
Essentially, this method would lead to simpler design, faster methods (except for initialization) and smaller object size. Please let me know if there are issues with this which I have overlooked. The only drawbacks I can think of is if we would want to dynamically alter these types at runtime, but this is currently not discussed in the article.
From Dimonte on reddit:
It seems to me that this is reversed in your text. By GoF's definition, it is the intrinsic state that is "context-free", and flyweight object may need extrinsic, context-dependent state passed to it if it needs it for some internal logic.
The Game Loop chapter talks about updating frequently, but makes no mention of the related pattern.
you mention that the if itself can be expensive enough to cause you to double check whether it's worth actually having a dirty bit, but in my experience, you can have your cake and eat it too.
http://www.dataorienteddesign.com/dodmain/node14.html#SECTION001423000000000000000
Move the calculation of whether to evaluate away from the evaluate itself and things flow better.
The first example can respond to multiple button presses in a single call. The later example that returns a command only handles one.
Should just change the first example to only process a single input too.
At: http://gameprogrammingpatterns.com/game-loop.html
"We bail out of the update loop when it’s less than the update time step, but not when it’s zero."
Remove "but"; this sentence confused me by implying that one does not bail out when it's zero. What you meant is to contrast "less than the update time step" with "zero", so you should write:
"We bail out of the update loop when it’s less than the update time step, not when it’s zero."
Strangely enough, this is similiar to how CPUs in modern computers work.
When a cache miss occurs, the CPU stalls: it can’t process the next instruction because needs data.
Instead of a giant constellation of game entities and components scattered across the inky darkess of address space
(From youresam on reddit.)
The ASCII art in the Tying back together section shows &hellip (in the HTML as <span class="o">&</span>hellip
) instead of ….
I noticed Bjorn* bjorn = new Bjorn(new PlayerInputComponent())
in the component chapter.
Preferable would be to pass a unique_ptr
with std::move
(an rvalue cast) as this would allow the component to be deallocated once the Bjorn
itself goes out of scope. The smart pointer could probably used in a number of other cases where raw new
s are used.
Typo is in heading: "Splitting behavior into one frame slices makes code more complex"
Should be
"Splitting behavior into frame slices makes code more complex" or
"Splitting behavior into one frame makes code more complex"
From tim6502 on reddit:
I get a 404 on the components pattern link: http://gameprogrammingpatterns.com/components.html[1]
"Most" is too strong a word for the number of games that have a scene graph. Popularity isn't relevant for the example anyway, so "many" is just as good.
Where you have a singleton resource manager class that maps strings (filenames, filenames+other params) to a Resource (and its descendants).
"Getting" a resource may reuse an already loaded or load it fresh from disk. I implement the getters as static methods of the Resource-descendants.
Resources are often const/readonly and can be shared by many pieces of code.
Resources handles are often reference counted (shared_ptr example?) and be automatically removed when the last reference is cleared. Alternatively, the resource manager may also cache some number of unused references in the hopes that it will be soon requested again.
(fyi: this is a great book/idea)
I was just going through the book online and it really seems that the focus should be on the final section of data modeling, there's real value there to the reader and deserves more attention.
That is where the real worth of the chapter is and the other sections are each conceptual dead ends. Instead they should be condensed down into little more than footnotes that show alternative definitions of "prototypes" that are clearly out of scope of the document.
There's a couple of other oddities in the top "prototype" section that uses "generators". These are usually called "factories" (since generators are something else).
Combining class-based object oriented data structures with the prototype data modeling (Steve Yegge calls it the "properties pattern") gives you a data driven approach to object creation without hand coding tons of classes (see Scott Bilas's paper for more on that).
I'm not sure you'd want to go into that explanation, but I'd certainly like to see the more beneficial concepts (by your own admission) expanded on and the less practical examples reigned in.
The following code uses PlayerInputComponent
but I think it should use BjornInputComponent
:
GameObject* createBjorn()
{
return new GameObject(new PlayerInputComponent(),
new BjornPhysicsComponent(),
new BjornGraphicsComponent());
}
Rather than typecast the floats when trying to figure out which cell a Unit belongs to in this article, it's clearer (and mathematically precise) to rather use the floor() function. It better describes the desired effect rather than a hazy typecast.
Minor typo: "Or the sync point may not part of the game mechanics." seems to missing a word.
From /u/kindall on reddit.
Toon324 suggests:
this is a highly useful idea and it is very easy to understand. I would simply expand it with the idea of passing a delta time variable and using that to calculate various things.
In this sentence in components:
the class touches so many domains that every programmer will have to work on it, but its so huge that doing so is a nightmare.
It should be it's, not its.
I think that the Don't subheading could use a pointer to the Type Object pattern. This since you get a chance to both avoid and retain the power of polymorphism.
if (physics_->isOnGround()) sprite = &spriteJump_;
Should be:
if (!physics_->isOnGround()) sprite = &spriteJump_;
At the end of the introduction, a comment in the code sample contains an HTML Entity instead of an ellipsis (or 3 periods).
bool update()
{
// Do work…
return isDone();
}
Not a big deal, but I think it would be safer to obtain xBefore_
and yBefore_
in the execute()
method instead of the constructor - otherwise no other Command may be executed between creating and executing this one for the undo
to work properly. And decoupling the creation and execution of Commands is one of the other big selling points of the pattern, right?
The Component pattern is already shaping up to be the longest write-up, but shouldn't ECS get some more elaboration? It could be the next step after No Bjørn at All?, except that it's just mentioned as a sidenote and passed over.
Do you intend to add it later, or didn't think it was worth elaborating on?
The link to the component chapter in the section "Subclassing entities?!" of the update chapter links to "http://gameprogrammingpatterns.com/component" instead of "http://gameprogrammingpatterns.com/component.html"
The bottom of the Double Buffer chapter has a chunk of preformatted text:
Frame 1 drawn on buffer A
Frame 2 drawn on buffer B
Frame 3 drawn on buffer A
…
The format script is incorrectly converted the last "..." to a &hellips;.
This code is given:
void Heroine::handleInput(Input input)
{
if (input == PRESS_B)
{
if (!isJumping_ && !isDucking_)
{
// Jump...
}
}
else if (input == PRESS_DOWN)
{
if (!isJumping_)
{
isDucking_ = true;
setGraphics(IMAGE_DUCK);
}
else
{
setGraphics(IMAGE_DIVE);
}
}
else if (input == RELEASE_DOWN)
{
if (isDucking_)
{
// Stand...
}
}
}
And this statement is made:
"Bug hunting time again. Find it?
We check that you can’t air jump while jumping, but not while
diving. Yet another field…"
However, it appears the isJumping_ flag is still true when we dive (unless setGraphics(IMAGE_DIVE); sets it to false?), thus pressing B would not allow another jump.
Did you mean to write this?
void Heroine::handleInput(Input input)
{
if (input == PRESS_B) { [...] }
else if (input == PRESS_DOWN)
{
if (!isJumping_) { [...] }
else
{
isJumping = false;
setGraphics(IMAGE_DIVE);
}
}
else if (input == RELEASE_DOWN) { [...] }
}
In the flyweight chapter, it's stated that:
In my tests while writing this chapter, there was no noticeable difference between using an enum or a flyweight.
and then:
Flyweights were actually noticeably faster.
immediately after.
So was there a noticeable difference or not?
I'm very interested with this book. But I think you can improve it more by using some the simple English language. It's very helpful for non-native guys like me. Thanks!
I would caution against recommending Service Locator. I think right now SL is going to end up going the way of Singleton, only it's going to take a lot longer because most SL is done with third party tools that are extremely easy to use haha.
I recommend reading this before the rest of my comments: http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/
I would mostly be reiterating Seemann's points if I were to explain everything, so I'm not.
I just want to add though that his points are not academic. I was using SL in an algorithm intended to be used as a DLL when I ran across that article. My thought was, "I mean, I guess it's possible that it could cause problems..." when QA came to me having wasted an hour trying to figure out why instantiating and using a class was not working. ("Key not found? What's that mean?") I immediately went through and switched the whole thing to dependency injection.
It's really a huge difference to have all of the dependencies required in the constructor (where null checking can also happen) than to have the dependencies checked at runtime to see if, hey, did those ever happen to get put in?
It requires a change in the way that one codes - because you have to have dependencies instantiated in the composition root - but that change is for the better, I think. It starts to break down the concept of "tiers" or "layers" that I think is detrimental to OOP, and it keeps code very loosely coupled without the kind of mushiness one can end up with if they have too much abstraction.
Anyway, I'm more in LOB app programming than game programming, so I know things can be different there - and these opinions are definitely not the norm even amongst app dev - but that's just something I've noticed from personal experience.
Looking forward to the book at any rate though, it looks awesome.
It should, like the other game loop examples do.
Hello,
I found this book through one of the C++ blogs in my reader, and I have to say that it's an excellent read so far. I really like your writing style, and you present the material in a way that is very clear and easy to understand.
I've only read the "Data Locality" chapter so far, and I have a comment about one of the sidebar annotations: "There’s a key assumption here, though: one thread. If you are accessing nearby data on multiple threads, it’s faster to have it on different cache lines. If two threads try to use data on the same cache line, both cores have to do some costly synchronization of their caches." IIRC, this comment would only apply if at least one of the threads tries to write to the same cache line. If all threads are reading, there should be no problem. This isn't my domain of expertise but I'd thought I'd bring this up so you can check it out.
Cheers,
Kevin
Cakez0r on reddit says:
On the topic of "Be careful modifying the object list while updating", the way I usually get around removing objects from the list is to walk the list of entities backwards.
It's worth mentioning that in an aside.
Just wondering, but it appears that bit and flag should be switched in this opening paragraph in Motivation.
With bits we call them "true" and "false". For flags, you sometimes hear "set" and "cleared".
I have always come across them the other way around, especially with ASM
In the part 'Cached world transforms' the aside for the image states:
'The lines marked with (☆) are the world transform calculations that are actually used. The others are all wasted work.'
But in the image the lines marked with (☆) are all recalculating the parrot.
Either the image has to be corrected to mark the lines which are really used or the aside has to be changed to reflect that the transform of the parrot is recalculated 4 times while 1 time would be sufficient.
"The downside of the free-for-fall."
I think it should be:
"The downside of the free-for-all."
Instead of having a private static member pointer and checking against NULL
(which should be nullptr
since C++11 anyways), it's more idiomatically correct to do something like the following:
class FileSystem
{
public:
static FileSystem Instance()
{
static FileSystem instance;
return instance;
}
private:
FileSystem () {}
};
Get rid of all of the leading underscores. Should be trailing (or none at all).
In the concrete example, it may be faster to not use the dirty flag and calculate world transforms every time to avoid a branch prediction. Mention this in an aside.
Pretty straightforward. If you are not logged in, the "file a ticket" link is to the GitHub 404 page. Logging in fixes this problem but there is no explicit suggestion that logging in is necessary or will fix the problem.
At: http://gameprogrammingpatterns.com/singleton.html
search/replace:
if it won’t be instantiated
it won't be instantiated
At: http://gameprogrammingpatterns.com/double-buffer.html
In the very last example on the page, you store 0 and 1 and swap them out. Why not use "current=1-current" to do the swap, and provide an accessor "next(){ return 1-current; }". This saves half the storage space and two-thirds of the CPU time in the swap.
So there.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.