• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.


  • Content count

  • Joined

  • Last visited

  • Days Won


Hodgman last won the day on July 14

Hodgman had the most liked content!

Community Reputation

51172 Excellent


About Hodgman

  • Rank
    Moderator - APIs & Tools

Personal Information


  • Twitter
  • Github

Recent Profile Visitors

65655 profile views
  1. Steam lets you generate as many keys as you like for your different steam versions / DLCs and then do what you will with them, including selling them on your own site. My gut feeling is they won't like your de-censorship patch situation, but maybe you'll be small enough to go unnoticed / unpunished... When GTA:SA was patched by the community to de-censor it, it was reclassified as adults only by some countries and even banned from sale!
  2. Ok, so write down your 10x ROI business plan, and go pitch it to venture capitalists. That's what startups all over the world do. If your business plan isn't terrible, it's not hard to find investors. Your profile says Ottowa, check out the startup scene there: https://teleport.org/cities/ottawa/startup-scene/ There's a startup there making an app that stores photos (um, google drive, dropbox, flickr, hello) who's disclosed $1M in investment and will probably do another investment round later this year. There's another that's making a VM for phones / android user profile system, which has disclosed $10M in investment. Or another that is making a automated spreadsheet to log gym equipment usage and has declared over $3M in investment. If you actually want to launch a start-up business, there's no reason that this kind of capital isn't available to you... however, most of us don't really want to launch a start-up, most of us just want to make games Re AAA: The average game-developer salary in NA is around $80k. GTA 5 had a total budget (development and marketing) of ~$250M. The core team was 100 devs, the total team included over individual 1000 devs, and there were over 60 voice actors (and a lot of licensed commercial music). Development period was about 5 years. Going off those numbers, the core team salaries alone add up to about $40M. Add on the 900 additional helpers, the voice acting, licensing fees and cost of business (rent, bills, legals, etc) and that's easily over $100M. That leaves $150M for a world-wide advertising campaign. You can expect a cost of customer acquisition of about $5 (for every $5 spent on advertising, you get one new sale of the game), so we can expect that from that $150M that they'd sell 30M copies. Opening weekend sales were ~15M copies and total sales are now 80M, so their marketing team did a very good job with that money. All up they've probably made about ~$2.5B, which is a 10x ROI from their initial spending -- the same that you're promising. If you think that you can do the same thing but better (without the "fat" and "secret handouts"), then go ahead and join the start-up scene for real and go get your investment.
  3. In my project they're used a bit for implementation-hiding purposes. C++'s ancient compilation model means that any code that's required to declare your private details also has to get included by users of your class. Ideally this just consists of forward declarations of those types and the damage is minimal, but sometimes it means including windows.h/d3d11.h/somemiddleware.h/etc, which causes huge swathes of implementation-specific details to leak out into your user's code... Which is bad for both practical build times and theoretical engineering reasons. Using an interface with a single implementation (and a factory/virtual constructor) solves this issue. When used for this purpose, interfaces are often implemented via ADTs or PIMPL rather than via an abstract base class. Remember C++ doesn't have interfaces as a language feature, allowing you to choose whichever implementation of that concept that suits you. That's the nice thing about C++ - you can write code that follows Javas idioms, or C's, or JavaScript's. We've got some interfaces that use ABCs, some that use ADTs, an d some that use a structure of function pointers
  4. Yeah I don't any more either. Interfaces, abstract-classes and concrete-classes all use the same convention.
  5. A $1M budget for an indie game isn't that unusual. Often the founders of new companies will "invest" their wages back into the company, which means they're owed the money on paper, but no money exists yet. e.g. A senior game developer could have a salary of around $120k pa. When they quit to start their own studio, they'll pay themselves that same salary. Let's say we've got two veterans who are "going indie". The company is founded by Bob and Alice, who sign employment contracts for a $120K pa salary. Every month, the company "pays" Bob $12k (the payslip / tax invoices say so), but Bob never receives any cash. At the same time, Bob "invests" $12k of his own cash into the company as a loan (at least the paperwork says so). At the end of the year, because Bob has "earned" $120k, he has to pay $32k to the tax office as income tax. Alice does the same thing as Bob. No money exists, and no money actually changed hands... but after one year, the company has $240K of debt on it's books -- it legally owes that money to Bob and Alice, who have loaned it to the company. The company declares on its tax paperwork that it has spent $240K on R&D activities, to which it is entitled a 45% cash rebate. The tax office pays the company a $108k reimbursement on its losses. The company partially repays Bob and Alice's loans, giving them $54k each (which after paying their own tax bills, leaves them with $22k each actual income, free from the taxpayer...), and the company still owes them $66k each. If they sell their company in the future, the new owners have to pay them $66k each (on top of actually buying the company). That's a simple two person team with no company expenses, and their on-paper budget for one year's work is around a quarter million If it was a four-person team, working for two years or more, and they had some actual expenses (hiring contractors, buying equipment, renting a cheap office space) then their company could easily be in the $1-2M range... And it's not that this is all just made up either -- that's the amount of money they'd have to make off their game to actually make quitting their jobs and "going indie" a worthwhile venture. That's the difference between "indies" who are already far into their careers and treat their independent work as a legitimate small business, and "indies" who are beginning their careers and make games in their spare time as a hobby. AAA games cost more like $100M these days, not $1M. $1M is the new indie.
  6. I don't have much input, sorry... But the human powered helicopter was also sci-fi/fantasy until it was recently built. This sounds like a fun concept.
  7. Here's the documentation: https://partner.steamgames.com/doc/sdk/api
  8. Ah thanks for the correction, I thought it was off the min/max value in the enum, not the min/max bits of the values in the enum. So to correct my example: enum Flags { F_1 = 1, F_2 = 2, F_4 = 4, }; Flags f = ...; switch( f ) { default: return Case_Other();//a valid compiler could assume this is impossible case -1: return Case_1();//a valid compiler could assume this is impossible case 0: return Case0(); case 1: return Case1(); case 2: return Case2(); case 3: return Case3(); case 4: return Case4(); case 5: return Case5(); case 6: return Case6(); case 7: return Case7(); case 8: return Case8();//a valid compiler could assume this is impossible case 257: return Case257();//a valid compiler could assume this is impossible - perhaps the underlying type for Flags is char, not int. } There's a difference between does not currently, and is not allowed to. "enum class" explicitly defaults to using "int" as the underlying type ("For a scoped enumeration type, the underlying type is int if it is not explicitly specified"), but unscoped enums pick an implementation defined underlying type. It's not inconceivable that a compiler could pick an uint8, and then assume that values above 255 are impossible. It's also valid for the compiler to invent a 3-bit underlying type and then optimize based on the assumptions that you can make about 3-bit variables. Unlikely, but allowed. It's not crazy for the compiler to make assumptions based on the strict wording of the spec either. For example, usually this code will print "ok!", but I managed to get it to print "what?" under GCC, which is also correct behavior if the compiler makes certain valid assumptions: int* test = new int(42); *(short*)test = 0; switch( *test ) { case 42: printf("what?"); break; case 0: printf("ok!"); break; }; Interestingly, other times, the compiler will try to be super clever and remove most of that code, leaving a call to global operator new, and a hard-coded call to printf("ok!")...
  9. It doesn't matter that it's silly. That's the rules of the language as laid down by the spec. It's the assumptions that your optimizing compiler holds up as golden. You break the rules of the language and the compiler is allowed to fuck you. e.g. you can play with pointers willy-nilly, but the optimizer is allowed to assume that you haven't broken the aliasing rules. float f = 1.0f; (*(int*)f) = 0; // note that int(0) and float(0) have the same bitpattern, so this should work just fine! Yay, clever! printf( "%f", f );//does this print 1 or 0? In practice, that will often print 0.000... but the rules of the language say that this program is invalid, so you could expect it to print 1.000 as well. The aliasing rule says that on the 3rd line it's accessed as a float type, so only the most recent write to a float type could possibly impact the value. The 2nd line can be optimized out or otherwise ignored. That's the specified rules of the language. Likewise: enum Flags { F_1 = 1, F_2 = 2, F_4 = 4, }; Flags f = (Flags)((int)F_1 | (int)F_2 | (int)F_4); printf( "%d", (int)f );//does this print 7? In practice, this will probably print 7... but the rules of the language say that the variable f is only allowed to hold values from 1 to 4 (inclusive), so you could expect this program to print out something entirely different, such as 4 as well. That might sound silly, but optimizers are built to follow the rules of the language! So, say you've written a switch statement that's designed to handle the 8 possible values that you expect the above 'f' variable to hold, the compiler is well within it's rights to assume that half of these cases are impossible as the spec says that it can only hold values 1-4, and therefore the compiler is safe to go ahead and simply optimize away those function calls completely out of existence. switch( (int)f ) { default: return Case_Other();//impossible case 0: return Case0();//impossible case 1: return Case1(); case 2: return Case2(); case 3: return Case3(); case 4: return Case4(); case 5: return Case5();//impossible case 6: return Case6();//impossible case 7: return Case7();//impossible } It doesn't matter that this is silly. These are the rules, and when you choose to break them, you are choosing to write code that could stop working at any time, and only happens to work right now because the optimizer has not done a good enough job to break your invalid code, yet. Choosing to write time-bombed code is silly. If you continue to use enums as flags after this, you're choosing to play chicken with your compiler. Good luck, and pray that it doesn't optimize as much as the spec says that it's allowed to.
  10. The quake/doom engines are all great. Fabien Sanglard's code reviews are great also - http://fabiensanglard.net - a good way to get up to speed on those code bases without having to decypher the architecture yourself. I learned so much of my own game programming knowledge from reading (and modding) the Half Life 1 code base. The engine is closed source, but the game code is available. The gameplay architecture is bad by modern standards (incorrect use of OOP everywhere) but the separation of engine, network, client and server responsibilities follows the Quake model closely, so is quite clean.
  11. Open Source

    Yeah I define an engine as "after you make a game, all the bits you can reuse to make a second game, are the engine". So the only way to prove an engine is complete is to make a game Or at least plan out a game and work out what kinds of frameworks and tools might be required.
  12. The logical order of the API and the physical order of the hardware doesn't have to match up exactly, as long as it behaves the same way. If a clever GPU decides to do the depth-test before the pixel shader instead of after, there's no way for you to know -- the behaviour is the same... except that performance will improve... so GPU's will do this.
  13. IIRC from the Frostbite papers, they validate against Mitsuba. Another studio that I've worked with uses Marmoset to preview all their assets, so their validation procedure was to make sure that the assets looked the same in-game as they do within Marmoset
  14. I use option #1 and #2 in different situations If re-exporting is a pain, fix your build pipeline I have multiple template types for #2. Storing offsets from the start of the file is actually harder to deal with at runtime, because you can't just use the variable like a pointer, as "dereferencing" requires you to know the address of the beginning of the file. What I usually do is to store offsets from the current file-cursor (offsets from the "fake pointer" field itself), which is simpler to use at runtime. e.g. For offsets-from-cursor, I use this template which has overloaded operators to make it look just like a regular pointer at runtime. template<class T, class Y=s32> struct Offset { const T* NullablePtr() const { return offset ? Ptr() : 0; } T* NullablePtr() { return offset ? Ptr() : 0; } const T* Ptr() const { return (T*)(((u8*)&offset) + offset); } T* Ptr() { return (T*)(((u8*)&offset) + offset); } const T* operator->() const { return Ptr(); } T* operator->() { return Ptr(); } const T& operator *() const { return *Ptr(); } T& operator *() { return *Ptr(); } static uint DataSize() { return sizeof(T); } bool operator!() const { return !offset; } Offset& operator=( void* ptr ) { offset = ptr ? (Y)((u8*)ptr - (u8*)&offset) : 0; return *this; } Y offset; }; Or this one for offsets-from-beginning-of-file, which isn't compatible with operator overloading: template<class T, class Y=u32> struct Address { const T* Ptr(const void* base) const { return (T*)(((u8*)base) + address); } T* Ptr(const void* base) { return (T*)(((u8*)base) + address); } uint DataSize() const { return sizeof(T); } Y address; }; And this is probably over-complicated, but it works for option #1: template<class T> struct Pad32to64 { union{ T data; u64 pad; }; operator T&() { return data; } operator const T&() const { return data; } T operator -> () { return data; } const T operator -> () const { return data; } bool operator!() const { return !data; } operator bool() const { return !!data; } Pad32to64<T>& operator=( const T& o ) { data = o; return *this; } }; template<int size, class T> struct Select64Wrapper {}; template<class T> struct Select64Wrapper<4,T> { typedef Pad32to64<T> Type; eiSTATIC_ASSERT(sizeof(Type)==8); }; template<class T> struct Select64Wrapper<8,T> { typedef T Type; eiSTATIC_ASSERT(sizeof(Type)==8); }; template<class T> struct PadTo64 { typedef typename Select64Wrapper<sizeof(T), T>::Type Type; }; struct Test { PadTo64<int*>::Type myPointer; };
  15. OpenGL

    Lots of games from that era would trace a single ray downwards to find the floor under the player's feet, then find the lightmap-UV coordinates at that point, then sample the lightmap at those coordinates and use it as a constant ambient value for the player.