• 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.

EarthBanana

GDNet+ Basic
  • Content count

    253
  • Joined

  • Last visited

Community Reputation

1794 Excellent

About EarthBanana

  • Rank
    Member

Personal Information

  1. The best thing, because of your custom requirements, would be to build your game engine from scratch Jk dont do that - thats a terrible idea.. But honestly what your trying to accomplish here contentwise is the equivalent time committment (maybe a bit less not sure)
  2. The problem with tackling a large project like this without having experience in completing some smaller projects is that most solutions to the problems that you talk about are learned from doing the smaller projects.. but more than that - completing projects, however small, builds some character traits that are absolutely required to finish larger projects - persistence and discipline.   To add to the above poster's comments on coding up larger systems - code is just a tool to do a thing right? You can waste a lot of time trying to "architect" code so that it fits some criteria that will make it future proof and able to scale. Why not just write the code to make whatever thing your trying to do right now work, and don't worry about it until you have to. If things are slow its a lot easier figuring out how to make them faster and improve the thing you have than trying to write code that will be fast when you have nothing. For example - you have a lot of events and encounters on a map and you are worried about it? Have you tried just sticking "events" and "encounters" in an array and processing them every frame from beginning to end? It would likely work just fine. All of this I'm saying is learned from experience - and learned from a lot of wasted time doing unnecessary things.   I would suggest a very, very small chunk of the game your talking about - and complete it.
  3. Check out Spriter or Spine   With spriter you can export good ol fashion spritesheets but save your projects so that you can easily switch clothing and animate your sprites within Spriter.   Spine has c API that will let you use the Spine animation data directly - this is a bit more involved/advanced but results in smoother animations. Last time I checked Spriter only had a library written to use this data with SFML.   In any case you can just export spritesheets and use the program to do your animation stuff. Saves a lot of time.
  4. I ran in to this problem when my frame rate was too high using a fixed time step with no interpolation - long story short you can end up having two updates in a single frame and this happens over and over causing the jitter - I believe its referenced in the above article mentioned. Don't have time to look over your code at this second but   A quick fix is to turn on vsync by calling glfwSwapInterval(1) - you might give it a shot. The other f.lux thing might be turning vsync on and off - I'm not sure though
  5. Introduction Serialization is the process of taking structures and objects along with their states and converting them to data that is reproducable with any computer environment. There are many ways to do this - it can be a struggle to figure out something that consistantly works. Here I will talk about a pattern or method I like to call pupping, and it is very similar to the method boost uses for its serialization library. Packing and Unpacking Pup stands for pack-unpack, and so pupping is packing/unpacking. The ideas is this; rather than create serialize/de-serialize functions for each object type and/or each type of medium (file, network, GUI widgets), create pupper objects for each type of medium bundled with a set of read/write functions for each fundamental data type. A pupper object contains the data and functions necessary to handle reading/writing to/from the specific medium. For example, a binary file pupper might contain a file stream that each pup function would use to read/write from/to. Explanation This pattern is fairly similar boost serialization, though I was using it before hearing of boost. It is useful in any case to understand it and possibly use a custom implementation so that no boost dependency is needed. The "pupper" is somewhat equivalent to the boost archive, and pup functions are equivalent to boost serialize functions. The code presented here is more simple than boost, and does not overload operators as boost does. It is as non-invasive as possible, and not template heavy. The idea is that any object, no matter how complex, can be serialized to a stream of bytes by recursively breaking down the object until reaching fundamental data types. Any fundamental data type can be directly represented by bytes. The process of saving/loading/transmitting the raw data is separable from serializing objects. It is only necessary, then, to write the code to serialize an object once and anything can be done with the raw data. The pupper pattern differs from most serialization methods in a few ways: 1) Read and write operations are not separated except at the lowest level (in the pupper object) 2) Objects that need to be serialized do not need to inherit from any special classes 3) Can be implemented with very small overhead, using no external libraries, while remaining extendable and flexible 4) Writing class methods, virtual or otherwise, is largely not necessary If polymorphic serialization is required, a virtual method is needed in base classes. CRTP can be used to aid in this process. This case is covered later. Instead of creating a class method in each object to provide for serialization, a global function is created for each object. All global functions should have the same name and parameters, except the parameter for the object that should be serialized. Making any object "serializable" is then just a matter of writing a global function. These functions can be named whatever as long as they all have the same name, but I find "pup" fitting. Some examples of pup prototypes for stl containers are shown below. template pup(pupper * p, std::map & map, const var_info & info); template pup(pupper * p, std::vector & vec, const var_info & info); template pup(pupper * p, std::set & set, const var_info & info); The pupper pointer and var_info reference parameters will be explained later. The important thing is that the serialization work is done in a global function, not a member function. The pup pattern is easiest shown by example. In this article pupper objects for binary and text file saving/loading are coded, and a few example objects are saved/loaded using them. An example is given using the pupper pattern along with CRTP to serialize polymorphic objects. Also, a std::vector of polymorphic base objects is saved/loaded illustrating the flexibility this pattern allows when using other library defined types (std::vector). So without further ado, take a look at the pupper header file. #define PUP_OUT 1 #define PUP_IN 2 #include #include #include struct var_info { var_info(const std::string & name_): name(name_) {} virtual ~var_info() {} std::string name; }; struct pupper { pupper(int32_t io_): io(io_) {} virtual ~pupper() {} virtual void pup(char & val_, const var_info & info_) = 0; virtual void pup(wchar_t & val_, const var_info & info_) = 0; virtual void pup(int8_t & val_, const var_info & info_) = 0; virtual void pup(int16_t & val_, const var_info & info_) = 0; virtual void pup(int32_t & val_, const var_info & info_) = 0; virtual void pup(int64_t & val_, const var_info & info_) = 0; virtual void pup(uint8_t & val_, const var_info & info_) = 0; virtual void pup(uint16_t & val_, const var_info & info_) = 0; virtual void pup(uint32_t & val_, const var_info & info_) = 0; virtual void pup(uint64_t & val_, const var_info & info_) = 0; virtual void pup(float & val_, const var_info & info_) = 0; virtual void pup(double & val_, const var_info & info_) = 0; virtual void pup(long double & val_, const var_info & info_) = 0; virtual void pup(bool & val_, const var_info & info_) = 0; int32_t io; }; void pup(pupper * p, char & val_, const var_info & info_); void pup(pupper * p, wchar_t & val_, const var_info & info_); void pup(pupper * p, int8_t & val_, const var_info & info_); void pup(pupper * p, int16_t & val_, const var_info & info_); void pup(pupper * p, int32_t & val_, const var_info & info_); void pup(pupper * p, int64_t & val_, const var_info & info_); void pup(pupper * p, uint8_t & val_, const var_info & info_); void pup(pupper * p, uint16_t & val_, const var_info & info_); void pup(pupper * p, uint32_t & val_, const var_info & info_); void pup(pupper * p, uint64_t & val_, const var_info & info_); void pup(pupper * p, float & val_, const var_info & info_); void pup(pupper * p, double & val_, const var_info & info_); void pup(pupper * p, long double & val_, const var_info & info_); void pup(pupper * p, bool & val_, const var_info & info_); A var_info struct is declared first which simply has a name field for now - this is where information about the pupped variable belongs. It is filled out during the pupping process, and so a constructor requiring field information is made so that it isn't later forgotten. The pupper base class defines the set of methods that any type of pupper must implement - a method to handle reading/writing each fundamental data type from/to the medium. A set of global functions named "pup" are declared and defined, establishing the fundamental usage of the pupping pattern. The idea is to be able to call pup(pupper, object, description) almost anywhere in code in order to serialize/de-serialize any object (that should be serializable). Creating a new pupper object type includes implementing a pup method for each fundamental data type. These methods are then used by the pup global functions, which in turn are used by pup functions for more complicated types. No matter how many new pupper types are created, the pup functions to serialize each object need only be written once. This is exactly what makes this pattern useful. To make all objects serializable to file in binary, create a binary file pupper. To make all objects serializable to file in text, create a text file pupper. To make all objects serializable to a Qt dialog, create a Qt dialog pupper. Some types of pupper objects may require additional information about the variables. For example, there are multiple ways a double can be represented in a GUI - a vertical slider, horizontal slider, spin box, etc. The var_info struct allows new information about variables to be added. Any pupper object that does not need that information can just ignore it. With the Qt example, a flag could be added to the var_info struct and used by the Qt pupper object. The objects that need to be shown in a GUI would then need to set the flag, and all pupper objects that don't have use for the flag ignore it. By making the destructor of var_info virtual, the var_info struct can be extended. This is useful, again, if creating a library that others will be using. It allows the user to create their own pupper object types and add any necessary data to var_info without needing to edit the library source code. There are a few reasons for using pup(pupper, object, description) instead of pupper->pup(object, description) or object->pup(pupper, description). The reasons for not using pupper->pup(object, description) are: 1) The base pupper class would have to be extended for every new type of object. If creating a library with extendable classes, the user of the library would have to edit the base pupper class for every class they extended in which the library is still responsible for serializing 2) The pack/unpack code would be separated from the object making it prone to bugs when changes are made to the object And the reasons for not using object->pup(pupper, description) are: 1) You cannot easily extend third party library objects (such as std::vector) to include a pup function - they would require a special function or wrapper class 2) Since many objects would not include a "pup" function, there would be inconsistencies with the pup usage. This is purely an aesthetics/convenience argument, and is of course an opinion. But I would argue that writing: pup(pupper,obj1,desc1); pup(pupper,obj2,desc2); pup(pupper,obj3,desc3); pup(pupper,obj4,desc4); //etc... is both easier to understand and remember than: obj1->pup(pupper,desc1); pup(pupper,obj2,desc2); obj3->pup(pupper,desc3); pup(pupper,obj4,desc4); //etc... If the same pup function format is used for everything, writing pup functions becomes trivial because they are just combinations of other pup functions of the same format. Creating concrete pupper objects can be easy - binary and text file pupper objects are included as an example. The definition code for them is boring so it won't be shown here - but the declarations are below. //binary_file_pupper header #include "pupper.h" struct binary_file_pupper : public pupper { binary_file_pupper(std::fstream & fstrm, int mode); std::fstream & fs; void pup(char & val_, const var_info & info_); void pup(wchar_t & val_, const var_info & info_); void pup(int8_t & val_, const var_info & info_); void pup(int16_t & val_, const var_info & info_); void pup(int32_t & val_, const var_info & info_); void pup(int64_t & val_, const var_info & info_); void pup(uint8_t & val_, const var_info & info_); void pup(uint16_t & val_, const var_info & info_); void pup(uint32_t & val_, const var_info & info_); void pup(uint64_t & val_, const var_info & info_); void pup(float & val_, const var_info & info_); void pup(double & val_, const var_info & info_); void pup(long double & val_, const var_info & info_); void pup(bool & val_, const var_info & info_); }; template void pup_bytes(binary_file_pupper * p, T & val_) { if (p->io == PUP_IN) p->fs.read((char*)&val_, sizeof(T)); else p->fs.write((char*)&val_, sizeof(T)); } //text_file_pupper header #include "pupper.h" struct text_file_pupper : public pupper { text_file_pupper(std::fstream & fstrm, int mode); std::fstream & fs; void pup(char & val_, const var_info & info_); void pup(wchar_t & val_, const var_info & info_); void pup(int8_t & val_, const var_info & info_); void pup(int16_t & val_, const var_info & info_); void pup(int32_t & val_, const var_info & info_); void pup(int64_t & val_, const var_info & info_); void pup(uint8_t & val_, const var_info & info_); void pup(uint16_t & val_, const var_info & info_); void pup(uint32_t & val_, const var_info & info_); void pup(uint64_t & val_, const var_info & info_); void pup(float & val_, const var_info & info_); void pup(double & val_, const var_info & info_); void pup(long double & val_, const var_info & info_); void pup(bool & val_, const var_info & info_); }; template void pup_text(text_file_pupper * p, T val, const var_info & info, std::string & line) { std::string begtag, endtag; begtag = ""; endtag = ""; if (p->io == PUP_OUT) { p->fs
  6. One of this years entrees for week of awesome used it actually and did pretty well https://drive.google.com/open?id=0B9VrclvlENaSRE9KOVlxSGlZT0E There was also a panda3d entree https://dl.dropboxusercontent.com/u/58334662/TheShadowsTwisted.zip Not a fan of python for games either though
  7.   Yeah you really can make it arbitrarily complicated depending on what's needed - for example I used this method to write network code for integrated systems that ended up being much more complicated than what is shown here.   I am trying to edit the code to clear up the spacing issue but I'm having troubles - it shows correctly in edit mode so I think some invisible formatting stuff has carried over from copy pasting - I might end just going through line by line and have the auto indent in the gamedev editor do the indenting.   Thanks for the feedback! 
  8. I just finished writing an article on this exact topic - its currently pending approval - hopefully some of the members interested in this topic will participate in the peer review!
  9. Dotty McDotface
  10. It seems to me that the cursor icon system should be reacting to the event that triggers the modal popup as well - placing the correct icon and making sure the state is set correctly before the modal pops up
  11. In c++ I use a register_component_type<T>(string guid) function which will hash the string id using a stanard/fast hash function and then store the string and type in fast access hash maps with the hashed string id as the key, although I keep another hashmap for the Type to hash id storage also.   Then - you can either have   GetComponent(int type) - the direct access one   GetComponent<T>() {      return GetComponent( type_to_hashid_map.find(typeof(T)) ); }   GetComponent(string guid) {     return GetComponent( fast_hash_func(guid) ); }   Where you use the hashed string id instead of the type within the dictionary. Given the type you can look up the hashed id (because you stored it using the register function) or given the string you can use the quick hash function you used to first hash the GUID.   Its also easy enough to write out the hashed string GUIDs to file so you can use them directly in your lua script - the hash function you use should always produce the same exact ID for any given string.   This is what I do in c++ - but seems like it would work fine.
  12.   There recently was another thread talking about "spaces" and I think this is where I was getting somewhat confused. I don't really use a specific engine - I have conglomerated a bunch of usage code for different libraries that I have used - OpenGL, OpenAL, libsndfile, assimp, glfw, glew, and stb_image - and recently I have been trying to gather it all together in to a sort of engine (oh and recently I've been working with getting the bullet lib working). I made some different systems for ui, sound, selection, rendering, animation, and applying hierarchy transforms - much of it written during this last game jam, but I'm really struggling with how to organize the world - because all though only a small subset of things are on screen at once, sometimes I need logic to be done on game objects elsewhere.   It seems that I have been using "scenes" as what was referred to as "spaces". I'm not really sure how to relate them to each-other, or what the difference is. I'm also confused about whether I should allow game objects to share components to have an instancing effect, or create some prefab object - this is more of an editor concern though - as I'd like to be able to have some behavior similar to Unity as it gets annoying to change each object.
  13. Why don't you just leave the specific system function calls to the user of the library - and not do the whole virtual thing?   What's the difference between   system->prepare() system->update(dt)   and   system->update() {     prepare();     // do update }   However, if you actually write functions that are obvious and don't try to make a formulaic game loop, it will probably be a lot more workable to someone using the lib. At least, you can make it possible by providing granular functions - but there's no point in granular virtual functions in my opinion because virtual means the engine will be calling them and you have the above situation.   I think this would be better, if in the game loop users could call whatever functions they need   while (loop) { system1->do_system_1_specific_stuff_1(); system2->do_system_2_specific_stuff_1(); system1->do_system_1_specific_stuff_2(); system4->do_system_4_specific_stuff_1();} }   Where you might provide some storage mechanism for the different systems. To make things easy for first getting a project set up you could do the whole engine.update(dt) thing and then have some set of default behavior provided using the virtual updates.   EDIT: An event based update method seems like it would be better (as frob above mentions) but then you need to implement an event system. If your planning on making an engine though - probably needed at some point
  14.   So - what exactly distinguishes a "space" from just a "scene"? If all of your systems, for example, only operate on things in a scene that you pass in as a parameter to the system's work functions?   I have sort of run in to this issue lately - but it seems like using "scenes" works the same as spaces, where all entities contain an id indicating which scene they are in and they cannot actively be in more than one at a time - but they actually live in memory in some higher world object.