Jump to content
  • Advertisement
Sign in to follow this  
  • entries
    12
  • comments
    10
  • views
    10488

About this blog

Hobby Motivation for the Professional Programmer

Entries in this blog

 

Journal #11: Combat Update

Combat In my last entry I mentioned the few things that were really remaining for my tactical gameplay. I spent the time since working on the weapons issue. I added a few more weapons definition entries and updated the ship definitions to be the owner of the weapon slots. Those slots define limitations of that weapon location on the ship like the maximum available firing arc. I also updated my prototype harness so that a bunch of the testing stuff that was in there has been removed and all that remains is stuff that should move forward as part of the tactical game. I make a copy of it first so that I still had a version with that testing stuff that I could go back to though if I need it. Seemed like a good idea to include some new pictures. The red tiles are those in the arc, a blue tile is the cursor highlight when it's within the arc and a green tile is the cursor highlight when it's outside the arc. The lower right still has the text indicating which player's turn it is and the upper right has a display string indicating the name of the arc being used. Here you can see multiple weapons & weapon selection with two different firing arcs coming from the same ship. I think I have a some technical debt to address before I move onto either of the other two tactical features I mentioned in my last post. The main one is support for STL containers in my reflection system. I need it for a few cases, but the bothersome case right now is that I can't properly initialize my ship definition weapon slots from the data file. And the temporary solution involves a const_cast which is usually an indicator you're doing something weird. Random I did a few other random things
I switched all the copy constructor or assignments from private & unimplemented to public and using the "= delete" modifiers (see Readings section below)
I added some macros to make it a little easier to use my function delegate object. There was a bit of type data duplication, especially when creating a pointer to a class member function. It's a lot easier to use and look at now.
I added a placeholder for localization. This may sound a bit crazy, but I'm having to add a lot of to-be localized strings at work so it's at the forefront of my mind and it's one of the things the Unreal makes pretty painless to do when you're working in UnrealScript. Since I don't actually need localization quite yet the entirety of my localization header consists of: typedef std::string localized_string. This way I can at easily identify the things that are display strings and when a real solution goes in (if ever) the compiler should catch just about everything that needs to be updated for me.
Readings I've had a few technical books on my desk to read for quite a while and have spent a good chunk of the new year working my way through them. They've been Effective Modern C++ and Effective STL, both by Scott Meyers, and C++ Gotchas, by Stephen Dewhurst.
C++ Gotchas was a little tough sometimes because it was written in 2003 so it's pretty ancient for the tech world. It would have been a better read for me while in college and a few of the "gotchas" aren't really as big of an issue if you're using C++11 or C++14.
I've only just started Effective STL but it looks like it's also pretty ancient by tech lifetimes (2001) but I've only just started it so we'll see how well it actually holds up.
Effective Modern C++ was pretty great. There were a few things I knew in the back of my head from looking writeups about the new features. My home codebase is still pretty small so it's easy for me to blast in some types of language changes. I had previously already gone through my code and replaced NULL usage with nullptr. As I mentioned above, using "= delete" instead of private unimplemented functions I'm on board with (since it more clear on intent and generates a compiler error instead of a linker one), so I made that change as well. I added a couple of things to my todo list for improvements that I might be able to make to certain things using certain features. I'll probably make a pass to add the override keyword in all the appropriate places as well as start using it for all new code.
While reading C++ Gotchas and Effective Modern C++, I've played around with the notion of writing up a coding style guide for my home codebase. I contributed a bit when we revamped the one at Volition to bring it into the world of C++ and it was kind of fun. It would be nice to have something like that around if I ever tried to get someone else to contribute to my projects.
Random C++ Gotchas musings
The "Pimpl Idiom" is also called the "Cheshire Cat Technique"?! How did I never hear this?! That is such a cooler name!
The example code for the pimpl idiom was pretty standard except that the structure used as the implementation had private members and accessor functions. What is the purpose in that? You're already isolated from the client code through the private-ness of the pointer and the API of the public data structure. I seems weird to then force your own code to go through a second API for data access. Maybe it was just copy/paste.
It suggested using 0 over NULL due to implementation differences in the macro. I couldn't get behind that. NULL indicates intent to the reader in a much clearer fashion. Shouldn't be an issue going forward as everyone should be using the built-in nullptr.

MagForceSeven

MagForceSeven

 

Journal #10: Combat

Over the last few weeks I've made some good incremental progress on the combat in my little strategy game. 1) I added shields to both my starship class definition as well as to the starship data component. (We're in space so what fun is space combat without shields of some kind). 2) I added a new component to act as a damage interface. In other engines you might have an IDamageable that the component would be able to derive from in addition to the regular damage tree. At the moment I don't support multiple inheritance with my component definitions (I'm developing in C++ so there no real distinguishing between what you're deriving from). I'm okay with this for now. For now in my engine it's just a separate component on the entity with a delegate that can be called. I considered the more traditional derivation with a virtual function, but opted for something that involves a little less boilerplate code to do something slightly different. If I hadn't already had this delegate structure sitting around (I mentioned it in my first post as being based on the impossibly fast C++ delegates found here) I probably would have done it that way. 3) Fixed some bugs in a couple of previously unused functions and added a few new small helpers to some of my other systems that were needed in order to make all the new combat bits work the way that I wanted them to. 4) Added to my Todo list because every time a programmer writes code, they find related things they want to fix or add to. Some are technical debt, some aren't.
Combat Now, I'm a huge fan of Star Trek (if you don't recognize my avatar image, that's were it's from) and I wanted my damage to have a bit of the feel I got from watching the combat of that show (mainly TNG/DS9/Voyager). To that end I want basically 3 things when it comes time to apply damage to a ship in my game. 1) Below a certain point, a weapon should do nothing. 2) Within a certain range, the shield takes the majority of the damage. 3) Above that range the shields take extra damage. Currently I'm basing that all these on the ratio of the weapons power to the shields power. So the more powerful the shield vs the weapon, the more effective the shield. For now I have it all coded, but it's hard to tell at this point the "fun" since it's all pretty garbage numbers. A few other things: 1) Each ship has 6 shield entries, one for each side of the hexagon that it's occupying. Right now they all start at the same value, but eventually I plan on that changing. 2) Some combat could apply damage to multiple shields at once. In this case (for now) it divides the damage equally among all the shields but still uses the full damage to determine the power ratio for how to apply the damage to the shield. 3) Right now once you get through the shields, the ship just has a bucket of hit points that is decremented by damage. Eventually I'd like that to be applied to ship systems and affected by armor for that hex side as well. Somewhat in the vein of Star Fleet Battles & similar games.
What's Next I feel like I'm really only missing three things from my tactical combat: 1) Real/diverse weapons. Right now all my ships have the same weapon with the same stats. Plus the weapon is using the general purpose stats component (Journal #6). Neither of which is ideal. 2) Energy use model. The idea is that each ship generates points from it's various power supplies and then moving and using weapons reduces that amount. Kind of like the action points used in the original X-COM games (not the new ones by Firaxis). Right now all the ships start the turn with 2 points. The place holder weapon costs 1 and movement (to any space on the board) costs 1. Technically I do have a placeholder value in the weapon for a cost but it's set to 1. The movement should use up power proportional to distance traveled with, I think, some max travel limit that is smaller than the total power available. Obviously the number of points a ship will start out with will have to be much higher than 2, but it was a good placeholder. 3) Pathing turning limits. I have basic A* pathfinding though the hex grid already. The part that is missing is that currently a ship can basically path to where ever it wants. The models have a facing, but if they're told to move to the tile right behind them they will rotate in place and then move forward into the tile. That may be fine for some games (and possibly even fine for mine for some ship types like fighters if they get added) but I want my combat to be maneuver driven. It's meant to mesh with the shield arcs and (eventual) weapon firing arcs. I think that once I get those pieces in place I'll feel good about where the tactical game sits and I'd like to move onto an overarching strategy element that would bind all the tactical combat into a cohesive whole. Then I can go about refining the interplay between those two elements into an actual game!

MagForceSeven

MagForceSeven

 

Journal #9

January has not been particularly kind to me. It started with getting sick (you always seem to pickup a bug of some kind from planes) and after getting over that I had wisdom teeth extraction to look forward to and recover from. In fact, I'm currently writing this entry on the last day of my 4 day weekend to recover from that particular adventure. Thankfully everything on that front has gone super smoothly and am doing really well. So on to the parts that everyone here is way more interesting to the folks here. I started 2017 with the decision that I wanted to move on adding elements that are more about gameplay than development utilities. As much as I like that sort of work, it's time to move onto things to actually making a game. I'll swing back to utilities for a change of pace or as needed to support gameplay. As I mentioned in Journal #6, I'm working on a tactical strategy game. I've got some basic movement supported already, so the main missing tactical element is combat. I added (for now) another stats component (also Journal #6) to act as the data for a weapon attached to the each unit. For now all the ships have the same weapon with the same values. The stats my weapons are starting out with are Range (how far it can deal damage), Power (how much damage it does) and Cost (how much of the ship's supply stat is used to use). Since I don't really have a good solution for UI, I'm outputting most feedback that would be UI updates to the standard out for now. I added to the starship data definition (Journal #7) to include the mesh information and then reordered my object construction so that given one of those definitions I could construct an object. I also swapped out the generic stats component that I was using for the ship's runtime data (health and power) with a component specific to the job of tracking starship data. Since this component was meant to have a reference to the data definition it was created from, I added support to my reflection system so that it knew about the data definition library. That way the JSON data I use can include a serialization safe string (as opposed to a doing crazy things with pointers) that the reflection system knows how to turn into a definition entry pointer. Lastly, for use on my starship component I wrote up a data structure for gameplay stats (not to be confused with the stats component) and modifiers to those stats. In a typical RPG this would be used for values like Strength or Agility or the like. The modifiers would be things applied by equipment (like +50 Str or +25%) while they are equipped. For now the modifiers only support addition and multiplication. The stat starts with a base value that is the value when there are no modifiers, then multipliers are applied and then the additions to calculate the maximum value for that stat. It also keeps track of the current value over time. So in the case of a Health stat, it's tracking your current health, maximum health, base health and all the modifiers to the base that determine what your maximum actually is. We'll see how that goes for now. New todos:
- Logging: I can generate output to the debug window but it's not really a log. At some point I'll want a logging solution that can save to a file and do some basic filtering on what output is saved.
- Reflection: Support for dynamic arrays. My reflection system already supports normal C arrays but to finish my gameplay stats structure it needs to support dynamic arrays (std::vector). I haven't decided yet if I'll just do support for vector or if I'll try to implement something that is more general right off the bat.
- Console: I realized I forgot to include scripts in list of console todos. It's nice to be able to write up a series of console commands in a text file that you can then reference repeatedly and across multiple executions. The console I worked with at Volition supported this and it was super useful.
- Strong typedef: This was something I introduced at Volition and thought I had a version of it here at home. When working in C++, typedefs are great but in a great many circumstances they just aren't typesafe enough. For this reason I wrote up (as have many others include one that is part of boost) a macro that simply wraps an instance of a type in a struct to prevent general type conversions from happening when you don't want them to. I need to find some time to recreate that in my home project. I guess I didn't need it, but I'd like to use it as part of how the stats and their modifiers interact with the clients that are applying the modifiers. New project idea:
- I mentioned in my first post a tool I had been working on for the Fantasy Flight game, Descent. A campaign tracker. Well I started collecting and playing another game by Fantasy Flight called Star Wars: Armada. I think it would be very interesting to put together a tool to help keep track of things there. It could even spiral out to three tools, Fleet Construction, Combat tracker, Campaign tracker (campaign play being a thing that was just released). I'd need to work on upgrading my copy of the wxWidgets library since the one I currently have isn't compatible with the version of Visual Studio I'm currently on. Really just an idea right now. Edit: I am aware of online tools for this game in regards to Fleet Construction so it might not be the highest priority tool of the three. Well, that's it for January of 2017!

MagForceSeven

MagForceSeven

 

Journal #8

Howdy GameDev.net! Welcome to 2017! It's been tough finding time over the last month, December is a tough month to carve out personal time. That's not to say I didn't get anything done, just not a whole lot in my hobby code. I was hoping to have some more time during my Christmas vacation but instead spent most of it sightseeing Seattle with my girlfriend. And I seem to have picked up a bit of a bug on our way back and writing code while sick and/or medicated is tough. The thing that I did get accomplished was a small refactor of my input code. When I had originally written it, I had included an API for working with keybindings. But since I wasn't actually using it anywhere it wasn't really battle-tested as it were. My input library included an enumeration for identifying the actions to be bound to, but that wasn't really extensible or flexible enough to be used in multiple projects without hard-coding game-specific references into the library. So I rewrote that API so that instead of mapping an enumeration to keys, I map strings to key combinations. Well not arbitrary key combinations, just a key plus some combination of alt, control and shift. As with all things programming, this worked pretty well except for one tiny detail. It turned out that (given the way I wanted to be able to write the client code) if I had two bindings, one bound to and one bound to + , then pressing the + would trigger both bindings! Imagine pressing ctrl+c to copy some text and it also added a 'c' to the document. That wouldn't do. My current solution is a priority system based on the number of modifiers. The potential downside is that when checking a particular keybinding, I also need to check all other keybindings associated with the same key and more associated modifiers. 'Potential' downside, at worst there are currently only 8 possible combinations of keys possible for any given key with modifiers. It's currently only 8 because I don't make any distinction between the left & right versions of the modifier keys. I don't expect anyone would every possibly bind all eight combinations of a key to a game command, but even in the worst case checking 8 combinations shouldn't be a big deal. Anyway, the priority mechanism means that if there is a key-binding for + and it's down, then anything bound to just won't be triggered. Similarly if ++ is down, then + won't be triggered. And this is just for active keybindings, so if the only thing bound to is without any modifiers, holding down one of the modifier keys will have zero effect on the input reporting. Here's looking forward to much new code in 2017!

MagForceSeven

MagForceSeven

 

Journal #7

I hope that everyone (at least in the US) had a good holiday. I took the week off from work and while I couldn't devote the entire time to working on my hobby code I was able to get a nice chunk of something done. First I took some code that I had written for my component system and generalized it a bit so that I could reuse it. I call it an 'instantiator' and it's designed to do two things. The first is to act as an object pool, managing resource allocations and memory reuse as instances are needed and discarded. The second function is to manage some super-simple type information to allow for fast and safe type checking and casting. The instantiator comes in two flavors 'virtual' and 'concrete', the virtual instantiator just does the type stuff and acts as a kind of place holder. It also acts as the base instantiator type, defines a static public interface that the client systems go through and defines the private virtual interface that the concrete instantiators implement to do all the allocation stuff. Lastly the virtual instantiator defines a static array of instantiator pointers that it uses to route all the static API calls to the instantiator for the desired class. The concrete instantiator inherits from the virtual one picking up the type information support and implementing the virtual memory management interface. Now to support all this, the classes using the instantiator (which relies heavily on templates) have a few required members to them for things like class name strings and other static members. I've setup macros to simplify a lot of these things, but really all's that left to do is declare a type and then declare an instance of either a virtual or concrete instantiator for that type in a cpp file at file scope. The constructor for instantiator then registers itself (during pre-main construction) into the static array of instantiators. The basic gist of the implementation looks like this:class virtual_instantiator{private: // a few class identification members std::vector parenting_types; static virtual_instantiator *set[ MAX_TYPES ]; virtual type* alloc_internal( ); virtual void free_internal( type* ); // other various system virtual callspublic: static type* alloc( ); static void free( type* ); static bool is_type_of( is_type, of_type ); // static versions of the other virtual system calls virtual_instantiator( type, parent_type, classname );};class concrete_instantiator : public virtual_instantiator{private: // memory allocation stuffprotected: // implementations of virtual interfacespublic: concrete_instantiator( );};
This obviously doesn't compile. I've attached the full header to this journal entry if you're interested. During system initialization (inside main) a static function is called for the virtual_instantiator which then calls the initialization function for all the instantiator instances. One of the primary things that happens here is filling in the parenting_types vector of bools. This basically makes a copy of the bools from the instantiator for the parent type and then sets the bool for the current type. Then anytime that I want to know if one type is part of another's tree it's just a bit check. As part of the instance allocation, I also store the most derived type into a variable of the instance so that I know what it was allocated as. Some limitations: it only supports single inheritance and it's currently limited to an unsigned short (65535) worth of different types. Other than that the tree of classes can be as deep or as wide as I want it to be. The single inheritance limitation doesn't bother me personally and 65K of types seems more than enough for one game (since any game specific type ids could be used for different types in different projects). Now, I had originally written this whole setup pretty specifically for the creation and management of components and it was working quite well. But I decided that I would also like it to manage my data driven type definitions, things like class or weapon stats. So I refactored what I already had a bit (mostly adding more templates) so that my components and data definitions used the same code but used different instances of the static instantiator array. This refactored version is what is attached to this journal. I was also pleased that for the most part this worked out relatively painlessly. I did have to do some looking up of more recent C++ template features to get a couple things working the way I wanted in other headers but learning that stuff is one of the reasons I want to make an effort on this hobby code. The main effort of my holiday coding was actually writing up the code for my data definitions types. This code consists of two parts, the data_definitions base class and a class I named definition_library. The data_definition class was mostly a bit of copy/paste from the component class; all the bits and pieces that are required to interact with the instantiator and the macro for declaring derived types. The definition_library wraps up access to the instantiator (forcing an additional construction requirement), handles parsing of certain json files into data_definition instances and manages a mapping of string names to the data definitions (the name being the additional construction requirement). The main thing I decided I wanted to really enforce is that when accessing any of the definitions that have already been created, was that they should be const. If you create an instance at runtime, the creation interface does return a non-const instance, but once you let that go and get it by name through the library, the only way to do it will give you const data. My reasoning behind this is that the definition structures are intended as application-static data. Once the game is running and has loaded up that data it should be treated as unchanging. Now for purposes of development it probably makes sense that I can tweak some of those numbers at runtime. For now, that task has been relegated to my todo list. I'll always have the option of making type specific console commands for the definitions that I specifically want to be able to tweak, but I think I'd like to find a way to leverage my reflection system to write a single console command as part of the definition library that can modify any member of any type. Lastly, once I had all that setup I built my initial test case of a type that actually derived from data_definition and had instances that were created when a file was loaded. Continuing the theme of game design I'm working through, the data definition was the start of information about ship classes. Right now it just has a hull class (cruiser, battleship, etc) and an optional modifier (command, missile, escort). Happy to answer any questions about anything in this writeup. I know I probably touched nerves of a few people mentioning components and/or reflection without going into a whole lot of detail. I do plan to do a journal about them at some point, so you can look forward to that. Probably save that for a week when I don't have a chance to write much code or make a major addition to them.

MagForceSeven

MagForceSeven

 

Journal #6: Kryptonite

I'm back! I told you Sid Meier's Civilization was my Kryptonite and it basically stole my last two weekends playing it. The first weekend was no real surprise and I had planned to just play it all weekend. But I got sucked in again the following one while doing a few productive things like laundry. In any case it's a very good continuation of the franchise and worth a look if you like that sort of game. Now, onto what I worked on this last week. I decided to put more console work off to the side (with appropriate notations on my todo list) in favor of something a little more in the vein of a gameplay feature. So to that end I implemented what is the core gameplay loop of a tactical strategy game (along the lines of XCom or Final Fantasy Tactics). Now I obviously already had the game loop doing all the windows messaging, managing frame processing and rendering. This was the gameplay loop to control the player's interaction with the game. I added a new component and couple objects to act as players. Right now this component consists of an array of handles which are the ships controlled by that player. I also added a new component to handle unit stats and added that to all the ships that I had created and added them to one of the two players. The stats component isn't particularly complicated right now, just an arbitrary mapping of keys & values. Long term I don't expect that gameplay will rely heavily on this, but it's really nice for experimentation and prototyping. And it's not unit/spaceship specific. Right now all the ships have two stats: Power & Supply. The game loop then consists of:

Player Turn Start - Set all that player's ships supply stat to their power stat value
Move unit - User clicks another tile, path the unit to that tile, decrement supply by 1
When supply reduced to zero, move the selection to the next unit
Continue moving units and rotating the selection until all units controlled by player have a 0 supply stat
When there are no units with available supply, move to the next player and return to step 1

This should be fairly recognizable to strategy game players and it's nice to have moved my program closer to "game" territory. I also added a few other related elements like:
tabbing to rotate the selection of the current unit
preventing pathing from occurring when the current unit has a 0 supply stat
preventing the current unit from becoming one controlled by other players if you clicked a tile that had a unit you didn't own in it. Using the mouse to change unit selection was already supported.

This is the point at which I would/should have a video to show off the various unit moves and player turn transitions but I haven't familarized myself with video capture tools quite yet.

MagForceSeven

MagForceSeven

 

Journal #5: Not a Holiday

I didn't have a whole lot of time this week. Instead there was a trip to a Renn Faire and touring a US Navy missile cruiser as part of Baltimore Fleet Week. I did find a little time to implement a search feature to my console. It searches through both the name and the description (or just one depending on the input parameters) and outputs the name of all the results to the console history. Now this isn't particularly exciting I know, but what I found along the way was a little bothersome. It turns out that there is not a case insensitive version of 'strstr'. Usually for every flavor of string function I've ever run across there's a version 'strcmp' and a version 'stricmp'. And I couldn't find a 'stristr', and a little Google searching latter confirmed there isn't one! That's crazy. So I wrote one really quick. I'm going to try to find another small thing I can work on this week because I won't have time during the weekend. Civilization 6 comes out Friday and that series is my Kryptonite. Seriously, I've taken days off from work in previous years to play it. So I'm going to be sitting on my butt all weekend playing it this time.

MagForceSeven

MagForceSeven

 

Journal #4: Holiday

I didn't do more than a smattering over this last week, mostly because I knew that I had today as part of a three-day weekend (Columbus Day). That meant that, apart from some stuff in the morning, I had a relatively huge block of time to sit around the house and just code. To start, part of my mouse controls was really bothering me. When I activated my console I would lose mouse input, or more accurately I would stop updating the render position of my mouse cursor. So I did the small amount of work (mentioned in a previous journal entry) to split up my logic control and move the mouse processing to the primary control loop. Which is probably where it belongs. Now my game loop looks like this (roughly):// init logic stack with logic instanceswhile( running ){ while( PeekMessage( ... ) ) { // message stuff } // calculate frame delta Input->Poll( ); // update mouse render position running = process_logic_stack( ); render_logic_stack( ); // render mouse cursor Graphics->Present( );}
I added an output history to my console so that all the commands and the strings that they decide to print are stored for immediate or later display to the user. Next I got a handle on the rendering of my console. Here you can see it in the single-line mode. After the user commits a command, this UI goes away. The command and all it's output are still committed to the history, so you can open up the normal console if something goes wrong. You can also see how the logic for the main game isn't processing the mouse position to update that blue tile highlight to be the one that is beneath the cursor (the white square). Here you can see the standard mode of the console. The last line is the text in progress (still need a cursor of some kind), and above that is the history. All the "testX" strings are what I typed and, because I don't have very many commands, all the 'fail' strings are the feedback output generated by the console. If it successfully executed something, it wouldn't print out anything unless the command itself printed something out. The history can be scrolled through with fairly standard PageUp and PageDown controls. The rendering was kind of a pain in the butt, but I only have myself to blame for that. I'd still like to get to an immediate rendering mode to simplify what the console is doing, but that was already part of my todo list. At least I didn't find any new work that I wanted to do because of what I was working on today. Features to still work in: text cursor, search, auto complete options I'd also love to hear from anyone out there with regards to features of console systems like this that they like that I might appreciate including both as a user and from a technical implementation perspective. Until next time!

MagForceSeven

MagForceSeven

 

Journal #3

So there is still plenty of features that I want (or need) to add to my console system, but as far as being able to execute semi-arbitrary commands at run-time it works. So at the end of the day this is what one of my console commands looks like:SF_CONSOLE_COMMAND_BEGIN( command_test, "A test command" ) const char * test_string = SF_CONSOLE_GET_ARG( const char * ); int test_int = SF_CONSOLE_GET_ARG( int ); float test_float = SF_CONSOLE_GET_ARG( float ); bool test_bool = SF_CONSOLE_GET_ARG( bool ); bool test_opt_bool = SF_CONSOLE_GET_ARG_OPT( bool, true ); double test_opt_double = SF_CONSOLE_GET_ARG_OPT( double, 0.0 ); const char * test_opt_string = SF_CONSOLE_GET_ARG_OPT( const char *, "default" ); const char * test_opt_string2 = SF_CONSOLE_GET_ARG_OPT( const char *, nullptr ); // Do stuff hereSF_CONSOLE_COMMAND_END
A few things of note:
All the code for defining a command is designed in such a way so that client code only has to include the header with these macros. They don't have to include & compile all the other systems level stuff. In fact that header should only be needed by the project main file that handle the frame loop.
nullptr - All my hobby code has been converted over to use this. It's a definite improvement over the old NULL macro.
SF_ - Since these are macros, they're all namespaced in the only way that you can namespace macros. SF is short for Starfire which is what I decided to name my library of code/engine way back when I started putting it together.
I'll probably need a different set of macros that can leverage my reflection information to covert strings to enumeration values. You can pass an enumeration type to the macros, but the string parameter will first go through a conversion to integer and then then integer will be converted to the enumeration type. Not terrible; user friendly for the person writing the command but not for the person trying to execute it.
BEGIN/END - I'm not as happy with having to do a BEGIN and END macro. I'd rather be able to do something more like:
SF_CONSOLE_COMMAND( command_test, "A test command" ){}
but that wasn't really in the cards given how I wanted to get the arguments. The BEGIN/END macros are roughly this#define SF_CONSOLE_COMMAND_BEGIN( name, desc ) void cmd_func_##name( const char * const * const params, const int param_count ) static const console_command Console_##name( #name, desc, sfcc_##name ); void cmd_func_##name( const char * const * const params, const int param_count ) { int _arg_idx = 0; bool _arg_error = false;#define SF_CONSOLE_COMMAND_END }
The 'console_command' type is just a struct with those few parameters. We're basically using the pre-main static initialization execution as our command registration mechanism. A pointer to it is then added to a singleton-ish array in the actual console system file. I don't foresee this as a problem since by the time that any other code is executing and any multi-threading concerns can come into play that array will basically be treated as read-only. Not that I have any realistic plans to do multi-threading any time in the near future. The parameter macros aren't really that interesting, just wrappers so that the console command only has to specify the type and default. They shouldn't have to worry about those function parameters or the '_arg' variables declared by the BEGIN macro. And the error flag is actually used in such a way that if one of the non-optional macros is used (so the parameter is required for the command to function properly) there is an early return from the function. I'm also a big fan of symmetry in code which is really the only reason that the END macro exists. I could have left the closing brace as just a "that's how you define these things", but that seemed a bit goofy. All-in-all I think it covers all the bases that I wanted. It's well insulated, dropable anywhere, flexible parameters. At least this next weekend I won't feel the need to spend quite as much time with LEGO Dimensions.

MagForceSeven

MagForceSeven

 

Journal #2: Momentum

No, I didn't do any physics code this weekend. I didn't have much free time this week, but at this stage it's important to recognize what I could get done to keep the momentum up. I continued to work on my debug console. I was able to add the mechanism for actually registering console commands in other parts of my code, parsing the inputs into the parameter strings and actually executing the command. I was also able to get started on the APIs for accessing the params inside the command. When the command is executed, I pass an array of strings to the function (basically an argv, argc arrangement if you're familiar with a console main function). I just want to write a few functions that can do the various transmutations of strings to more useful local types. At my previous job I wrote some really nice code (I thought) combining macros and templates to read and write the parameters from a Lua stack object. Now, it won't be able to be quite as fully featured as those were (I'm missing all the type information that the Lua stack made available) but I think it will do a good job. I'll share some example code when I'm done with it. And a new thing for my todo list: Because of the way that I layer my execution, right now when I open my console it freezes my mouse processing because I basically pause the processing of the layer beneath the console. That's not really ideal so I need to update and split my control logic so that the gameloop is making two separate calls to do the processing and rendering. Then the main loop can be in charge of the mouse like it probably should have been from the start. The good news is that the one control function I'm calling right now, internally it is already splitting up the processing and rendering so this shouldn't be a terribly time consuming fix/improvement.

MagForceSeven

MagForceSeven

 

Journal #1: Black Triangles

It's been a week and change since I decided to launch my developer journal and I actually got some things accomplished. It's hard not to compare my hobby development with what I do in the office every day. On the one hand, it doesn't feel like I really accomplished a weeks worth of work. On the other hand I have other priorities/drains outside of the office that don't allow for the same kind of large blocks of time that I'm used to from professional development. I suppose that's just the nature of hobbies, right? There's also a weird symbiosis with work that, at least this week, influenced what I decided I would like to work on. I was doing an automatic test harness that could play the tactical battles of XCom to hopefully spot issues faster. Because of that work, I decided that what I really needed in my hobby project was a console and something generic to handle command line arguments. Neither of those sound particularly important, but it's easy to notice when they're not there. Plus I figured that they were small enough things so that for my first week at this I could have something crossed off my todo. Which brings me to a short tangent: Black Triangles. A number of years ago I came across a blog post called Black Triangles talking about tasks that don't look like much but have a lot of meaning. If you haven't heard the term, go read the story. When I first read it, the story and term struck a real cord with me because it described a lot of what I was doing and what I've continued to do in my career. On the Saint's Row games, I had a tendency to do some big refactors to improve on an aging code base. As a systems engineer, I tend to do work on things that are almost impossible to point at something in the game and say "I did that thing". And I'm okay with that. I've found the Black Triangles to be really interesting technical challenges. It's also describes what I focused on this week; not direct features per-se, but things that will allow me to work smarter, faster, better in the future. So, first off I wrote some code (I wouldn't even call it a system) to parse the command line and throw all the data into a map so that anybody else could check what was specified when the game started up. Not earth shattering, but command line options are so useful that it was easy to bang out last weekend to get some momentum going. Next I started on my console. Almost immediately I noticed that I had a problem with how I do my rendering. It's all currently done with registering objects with a scene and rendering that scene from frame to frame. Which is great for most game things, but it's a little much for rendering a console to say nothing of the kind of debug rendering that I will probably need in the future. For a moment this was a bit disheartening because I didn't really want to spend my week adding rendering support, so I didn't. I added it to my todo list and moved forward on the console making use of old school printing to the debug output window. Along the way I found some small things I absolutely needed to add to other supporting systems like a function here, a function there. I reordered my enumeration of keys I use with my input wrapper so that all the alphabetical keys were together instead of being interspersed with the other keys that are on the same rows on the keyboard (or at least a QWERTY keyboard). I also tried to take advantage of the keybinding system that was part of my input library but ran into a snag there too. It seems I wrote it so that it basically maps from one enumeration (the gameplay actions) to the enumeration of keys, which sounds totally reasonable. Except that that enumeration lives in the wrong place right now, the input library should be game agnostic and shouldn't have an enumeration of gameplay actions! So I'll skip that for now and just do the regular key checks against key enumeration and add another thing to my todo list. Even at work that thing always seem to grow faster than things are marked off. I didn't finish the console, I'll set it up with rendering without the immediate mode stuff eventually. But for now I can open & close it (so says my debug output) and I can edit (what will be) the command line including arrow keys, backspace, delete. It's also got a switch so that I can open it up normally or in a mode that will just show the command line and will go away after inputting the command (it's one of the things I like about the Unreal console). That's a Black Triangle for you, it doesn't sound like much but there's a whole lot more going on underneath than what is apparent. General Summary: Completed:
Command line param cache

Ongoing Console work:
Actual console commands, registration mechanism and execution
Tab completion
Command history (ideally from previous executions of the app)
Rendering

New Todos:
Immediate mode rendering
Input refactor to eliminate an enumeration

And now that you've reached the end you should read Black Triangles.

MagForceSeven

MagForceSeven

 

Introduction & Motivation

Perhaps it's because I'd just like to do more hobby programming. Perhaps it's because a friend of mine (slayemin) has just published a game of his for early access on Steam. Perhaps my girlfriend keeps super-productive on the weekends and want something other than playing video games to do with that time myself. Perhaps work just doesn't scratch the same engineering itch it once did. I'm not really sure but I'm pretty I need something more than just a text log at home ('cause that obviously hasn't been working). Working with Unreal 3 is definitely partly to blame (more on that later). So, after looking over slayemin's journal I decided to start one myself on the theory that I'd be a little more motivated if other people were judging me for not posting for a while. Guilt is a powerful tool :wink: I don't really expect anyone to call me out on that sort of thing but it's at least possible. And if someone reading this wants to make it their mission to keep me honest, well so much the better for both of us. That's my motivation for this journal, to try another tool to advance my hobby. I hope this also gets me to be more involved in the community. I've lurked here on and off since at least college (2000ish) even though my profile join date is 2010. My quicky resume: By day I'm a Senior Systems Engineer at Firaxis Games in Baltimore. I've only been here a little while but helped ship XCom 2 (at least as of this writing). Before that I worked at Volition in Champaign, Illinois. While there I helped make Saint's Row. You may ask, "But there have been 4 of them. Which one?" and I would answer, "Yes" because I worked on them all. Not really my kind of games but fun to work on. And lastly, before that, I attended DigiPen. All in all that 5 titles in 12ish years. Not too bad. Technically I have a credit on one more, Red Faction: Armageddon, because I was in a shared technology group but I don't really count that since nothing I was did actually applied to that title. Which I guess brings me to my goals with my hobby programming. Unlike a lot of other hobbyists, I'm not particularly concerned with a large scale release of a game. Would it be nice? Sure. Would it be cool? Sure. But I'm not an artist and I'm not a designer and I very much understand the impact of both of those professions on a quality title. That means I don't have to be looking around for engines or frameworks to reduce my time to a product I can shop around. Plus I use an engine (heavily modified Unreal 3) every day so my hobby programming is meant as a way to explore or experiment in ways that I can't at work. It also gives me the control to do whatever I want, where ever in the code I want (like converting over to new language features). Engines are great, but at some level there's just a limit to what you can rip out, rewrite, or re-engineer. Like I said, I already have that at work. I don't need it at home. Now, I wouldn't call what I currently have an engine. Not exactly. It's more like a loose collection of libraries I've written (C++) and attempted to keep in a reasonably organized way to be able to share between projects that I start. I've written almost all of it because of that OCD-like control I talked about wanting above and I don't really want my hobby programming to be spent gluing together 3rd party bits and pieces. I want to (mostly) build, not assemble if that makes sense. The only a few places that I've really outsourced any code are:
DirectX because that's the graphics pipeline I've used since high school and I don't care enough to jump, and D3D9 (no seriously that's what my code still uses! :lol: ) is super easy
a JSON parser because writing parsers in annoying, time consuming and error prone
WxWidgets, but only for UI for Windows based programs

And I won't mind including more libraries in the future because a library has limited scope and impact in a way that an engine doesn't. In fact, given my experience on Saint's Row, I'll probably integrate Lua as a scripting language. Or Python since I used that too. Plus libraries are easy to hide behind custom abstractions, in my case D3D is hidden away completely, the JSON less so. Part of my problem might be the number of projects I have "in progress". I won't go into much detail about them here, perhaps a followup journal entry, but to summarize there's 3 programming solutions and 2 design documents. However the design documents are mostly historical and I haven't made additions to them in a while. One of the programs is a campaign tracker for Descent: Journey into Darkness by Fantasy Flight Games, which is of less use since moving to Baltimore meant leaving the friends that actually owned the game that I would play with. I'd still like to finish it but upgrading Visual Studio threw a wrench in its use of pre-built WxWidgets binaries. To close I thought I'd list a few of the pieces of tech that I have in my libraries. I don't claim any of this as revolutionary or special other than to myself since I wrote it all. Consider it a snapshot of the systems I have in place as of today. There won't be much detail here but if anyone wants to pipe up in the comments about a specific system I'd be happy to do a more detailed write-up. So here we go:
Static Initialization time C++ reflection information (using a combination of macros and templates)
Component based object system (with type-safe dynamic casts that doesn't use RTTI)
Flexible delegate structure (based on the impossibly fast C++ delegates, but not using that code directly)
General event manger
math library with vector/matrix/orientation types and all sorts of utility functions
Collection of assert macros (based loosely on what I worked with at Volition)
A finite state machine
A priority queue using an internal heap/tree structure
File Cache data structure (with an asynchronous loading API even though it's not asynchronous under the hood quite yet)
Hexagonal gameboard with various utilities for working with hexes. Basically a height-map with a height for each hex tile. Some pathfinding support as well.

Two biggest todos:
A Redscreen system (to display issues that aren't quite asserts but should be attended to)
A Console (usually accessible in PC games from the '~' key)


MagForceSeven

MagForceSeven

Sign in to follow this  
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!