Just finished this other boi!! Critical Fail, Sarah Lindstrom, 2017
Justin Gerard - https://www.amazon.com/Books-Justin-Gerard/s?ie=UTF8&page=1&rh=n%3A283155%2Cp_lbr_one_browse-bin%3AJustin%20Gerard - http://gallerygerard.tumblr.com - http://www.gallerynucleus.com/artist/justin_gerard - https://twitter.com/HiGalleryGerard - https://www.behance.net/justingerard - http://quickhidehere.blogspot.com.es - https://www.etsy.com/people/JustinGerard - https://www.facebook.com/HiGalleryGerard - https://www.instagram.com/anniestegg
Geek Art by Jeff Langevin
Erosion
I was thinking about erosion, prompted by this blogpost from “Entropic Particles“ about taking a generated terrain and adding water erosion and rivers.
Erosion is frequently a good next step to improve a generated terrain: after the geologic forces, the water cycle is probably next most important force that shapes our landscapes. The catch is that calculating a river requires knowing the shape of the entire landscape: the Mississippi drainage basin encompasses a huge swath of the continent.
If your generator is section-by-section (such as Minecraft’s) and you try to generate rivers as you go along, it’s fairly easy to end up with rivers that go in loops if you’re not careful.
Still, rivers are important enough to human habitation that they’re often worth the expense. (Try a multi-level layer-based approach if you need open-world rivers on the fly.)
Erosion isn’t just about rivers, though: it adds a history to any kind of terrain. (And for smaller scale objects, weathering is equally important; automated weathering systems are useful tools for texturing assets.)
I haven’t tried the particular algorithm described in the blog post yet, but the results certainly look promising. Using a Delaunay graph of the terrain, you calculate the flow for each node. With the tree of the fluvial network giving the volume and direction for the water, the erosion can be calculated based on the slope of the terrain.
This is all much cheaper than fully simulating the erosion. And since performance is one reason why erosion isn’t used as often as it could be, that’s a big advantage.
Of course, I’m going to keep looking for other erosion algorithms too, because as I mentioned in the last post, it is often a good idea to have multiple ways to accomplish the same goal, so you can choose the best fit for the problem at hand.
A Thin Binary Serialization Mechanism
So this time I was playing around serializing things in binary files. Because who doesn’t want to read back the data in a form ready-to-be-consumed by his/her program with a single line of code?
Step zero is the obligatory Note that I’m in no way a C++ expert and the code you see might be a big mess. Born to improve nonetheless…
As a first step we need a simple interface to know what can be serialized. Add in this a forward declaration for our Serializer. Something like…
class Serializer; class Serializable { public: virtual void SaveTo (Serializer *s) const = 0; virtual void LoadFrom (Serializer *s) = 0; };
Any object that wants to be serialized needs to implement those 2 methods and declare what needs saving and loading. For example our game’s Character class may do:
void SaveTo(Serializer *s) const { s->Write(mName); s->Write(mCombatStats.ArmorClass); s->Write(mCombatStats.AttackBase); s->Write(mCombatStats.AttackSpeed); s->Write(mMainWeapon); s->Write(mSecondaryWeapon); } void LoadFrom(Serializer *s) { s->Read(mName); s->Read(mCombatStats.ArmorClass); s->Read(mCombatStats.AttackBase); s->Read(mCombatStats.AttackSpeed); s->Read(mMainWeapon); s->Read(mSecondaryWeapon); }
In this example mName is of std::string type. mCombatStats is a struct that has many attributes but we want to track only those 3. Finally mMainWeapon and mSecondaryWeapon are instances of a Weapon class that implements the Serializable interface too.
The second step is defining how the Serializer works. That is how those Write and Read methods are implemented. Let’s focus on these and leave the actual file handling aside… (full source link at the end of the post)
template<class T> using IsScalar = typename std::enable_if< std::is_scalar::value >::type*; template<class T> using IsSerializable = typename std::enable_if< std::is_base_of::value, Serializable >::type*; template<class T> using IsString = typename std::enable_if< std::is_base_of::value, std::string >::type*; class Serializer { public: //[...] // * Writing methods... template<class T, IsScalar<T> = nullptr> void Write (const T& value) { //[...] fwrite(&value, sizeof(T), 1, mpFile); } template<class T, IsSerializable<T> = nullptr> void Write (const T& value) { //[...] value.SaveTo(this); } template<class T, IsString<T> = nullptr> void Write (const T& value) { //[...] int size = value.size(); fwrite(&size, sizeof(int), 1, mpFile); fwrite(value.c_str(), size, 1, mpFile); } // * Reading methods... template<class T, IsScalar<T> = nullptr> void Read (T &value) { //[...] fread(&value, sizeof(T), 1, mpFile); } template<class T, IsSerializable<T> = nullptr> void Read (T &value) { //[...] value.LoadFrom(this); } template<class T, IsString<T> = nullptr> void Read (T &value) { //[...] int size; fread(&size, sizeof(int), 1, mpFile); char* tmp = new char[size+1]; tmp[size] = '\0'; fread(tmp, size, 1, mpFile); value.assign(tmp); delete[] tmp; } //[...] };
Using SFINAE through C++11’s std::enable_if (header <type_traits>) and some extra trait classes like std::is_scalar and std::is_base_of we are able to provide a different implementation for each type of attribute that is being written on the file.
Scalars like int, float, bool, enumerations etc are detected and handed on the proper Write or Read method through
template<class T, IsScalar<T> = nullptr>
which expands into
template<class T, typename std::enable_if< std::is_scalar<T>::value >::type* = nullptr>
by the using… alias-declarations defined right before the class.
Using the same technique we handle std::strings and all objects that are based on the Serializable class by delegating the Writing/Reading to their respective methods.
This way a whole hierarchy of composed objects can be serialized and de-serialized to/from a single binary file using one line of code!
// Write character Character ch; ch.mName = "Aneleith the Legendary Ranger" ch.mCombatStats.ArmorClass = 16; ch.mMainWeapon = Weapon("Bow of the Relentless Bear"); Serializer ser; ser.SetFile("character.dat"); ch.SaveTo(ser); // <<< All is needed to save // Read character Character ch; Serializer ser; ser.SetFile("character.dat"); ch.LoadFrom(ser); // <<< All is needed to load
I think this is pretty straight forward and simple though needs some more stuff to actually be useful. One major feature needed is handling collections like arrays/vectors and dictionaries/maps. Which will keep me messing with it for some more time…
Anyway, a Gist with the full source code can be found here
If you made it this far, thank you very much for reading and I would like to see your constructive critique in the comments section that follows…
Why do you think big developers have become so cagey about alpha and development footage/media? Back in the early 2000's they seemed all to happy to talk about it. Now it seems like only the Indie developers are interested in doing that (Be it by screenshots and blog articles or an open alpha/beta)
There’s a lot of reasons and @askagamedev will probably answer this better than me but the two big reasons that go hand-in-hand IMHO
1) super duper increasing budgets, especially marketing wise, plus the saturation of the market, means you need to go for a single huge marketing push to try to seize as many people’s attention at once
2) there is a non-negligible portion of gamers who think they know everything about making video games, and start witch hunts when something that was talked about in alpha/beta stages doesn’t make the cut to the final product
Definitely agree with both of these. #2 above is the general root of it all - we have stuff that gets cut during production all the time. If we mention it in marketing material, fans will take it as a promise that it will be in the final game. That said, I’d also add a few other factors of my own:
- The internet remembers everything forever. This wasn’t as big a thing back in the early 00′s because the lion’s share of game marketing was primarily done through other media - magazines, demo discs, television, etc. Most video was very rare - usually bonus stuff on the disc after you bought it, since the technology wasn’t there to share video very easily. Today we have the internet which serves as both a way to disseminate info and a way to archive it. This means that (like politicians) anything we said that we didn’t deliver on will be held over us in archived form forever.
- There are a whole lot more people who care about games today than there were back in the 00′s. Diablo 2 was a huge game that came out in 2000 and sold a whopping four million copies in its first year. Modern Warfare 3 (2011) got 30 million sales.
So really, it’s ( way more people + easier to share information + everything is remembered forever + massive budget spent on marketing and development ) x chance of “BUT YOU PROMISED!!!“ = playing cards much closer to the chest.
Got a burning question you want answered?
- Short questions: Ask a Game Dev on Twitter
- Long questions: Ask a Game Dev on Tumblr
- Frequent questions: The FAQ
Generating Naming Languages
For NaNoGenMo 2016, Martin O’Leary created a fantasy map generator, complete with names in a generated language. Now, he explains how it works.
The basic idea is based on Mark Rosenfelder’s Language Construction Kit, though Martin’s current version is the result of further experimentation. It starts by generating some nonsense syllables constructed out of a set of vowels and consonants, and building up into phonotactics, introducing an orthography, and generating a morphology.
The result is a name generator that can create interesting, plausible-sounding names that sound similar enough to be part of the same language…and can go on to generate another language that has the same properties but sounds completely different.
If you’re looking at generating a language, or even in just learning how to think through how a generator works, this project is a great example.
The code is on GitHub, in JavaScript and Python.
PANow - Paul Weir - May 2015
A presentation by Paul Weir all about procedural audio. Paul Weir is the audio director and sound design for No Man’s Sky. Generative music is one of his big interests, and the presentation covers a lot of examples from the past twenty years of games. Some of the systems he worked on, some of them are ones he likes or finds influential.
Among the things discussed: Ballblazer, LucasArt’s iMuse, Ghost Master, Spore, Thief 4, the challenges of composing generative audio, the inner workings of some of the systems, retail stores using generative music, and generative music tools.
Where is the best place to learn the basics of procedural generation? I've looking to start but can't find any good leads.
Good question! Really, it depends on what skills you already have. I’ve posted a couple tutorials to the blog, but without much regard to skill level. I’ll almost inevitably be posting more in the future.
Last year, the Procedural Generation Jam had a big list of tutorials: http://procjam.tumblr.com/post/99689402659/procedural-generation-tutorials-getting-started That’s a great starting point.
If you don’t have much programming experience, it might be worth prototyping some systems on paper, with dice, cards, or other tools. These can be useful in themselves, and it is good practice for the kind of thinking that’s behind all procedural generation.
Lastly, I want to encourage you to just dive in. Procedural generation is always going to be experimental because it revolves around finding unexpected ways to combine different parts to get new results. Start with something that makes something, even if it is a really simple something, and keep finding new ways to tweak it and combine it until you’ve discovered something new and unique to you.
Anyone else have any suggestions for good tutorials?
I want to get my hands on this book sometime. I hope that a more solid knowledge of the topics covered will give me a better direction coding graphics stuff. Following the try-and-fail-until-you-succeed method -like I have done lately- doesn’t make you feel really productive when thinking the time spent. Although the “aha” moments are bold and plenty.
‘Why are the stories in video games so bad?’ by Leigh Alexander