Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Monday, April 15, 2019

battleMETAL - Quick update 4/15/2019

Where the hell have you been? 

I know I know, I'm really bad at maintaining a blog. So I've been busy with a slice of life, some major tech fighting with battleMETAL (oh we'll get into it soon), and starting a new job soon. I do want to return to the 'METAL Monday formula, its just that blog writing was cut from the schedule because it was something that could be sacrificed. I'll return to blog posts on May 6th, 2019 and we'll keep diving into the bucket of fun that is battleMETAL. 

In the mean time, the game itself is pretty much feature complete and I've moved onto level generation. I have a tentative Beta release date of Q3 2019, and then we'll see how things look from there. Stand fast, DEAD HANDS, your activation is pending.

 

Monday, January 28, 2019

battleMETAL - And Yet, Somehow it all works - part 3 - Animatics

Quite an animated conversation

One of the feature’s I wanted to exist in battleMETAL was that of ‘animatics.’ For background, an ‘animatic’ is like a glorified slideshow. These are usually defined as a series of static images displayed in a sequenced order - like a super slow animation. Why would battleMETAL need these exactly? Why for character transmissions of course. I wanted characters to be able to talk at the player, or about the player to other characters in a way that player could visually see and understand. Radio transmissions that don’t show some sort of image are hard to follow in the ebb/flow of a video game. The concept of a ‘radio operator character’ for players to interact with is also a long-established mechanic in gaming.


Part of the original scope of battleMETAL was that the player won’t do any interacting with characters outside of combat. This was mainly due to time and resource constraints, but also because of the story and who the player is in this world. However, the player still needs some things to go off of when playing the game, so I felt that I could implement workable animatics to cover this gap. The system I finished is ‘good enough’ but probably could use some refactoring to make it ‘best’.


I started with CSQC, the animatics being an entirely client-side event, in my mind. I created a short set of api functions to handle the flow of the animatic system. The overall design is something along the lines of:
 

    Receive event from server
    Load animation file
    Validate file
    Setup playback variables
    Render frame 1 
    Render next frame
    End playback


The kick off is the server sending a command to the client to begin an animatic event. Quake was designed from ground up as a client-server game even in single player. Single Player in vanilla Quake is just a local game server with a max player count of 1. So even though battleMETAL only has 1 player in its server, the code still treats that player like any other remote-connect client in the code, which I think is a good thing. On the server, I created a custom map object, event_animatic that can be triggered by player touch or by other map objects, which sends a command to the target client to begin the animatic.


When the player’s CSQC receives the command, in this case changing the player’s “state” variable to _ANIMATIC, the CSQC begins the playback of the animatic. First step is loading the file. I decided that storing animatics in plaintext files was super handy both for readability and performance. The game engine doesn’t need to keep possibly dozens of animatic scripts in memory during gameplay, and because animatics are a low-delta event with no read/write commands, having the game load them from text files seemed like a good approach. I’ve always enjoyed the JSON syntax for data storage, considering it a better alternative to XML. Leveraging the Darkplaces source port’s ability to parse text files, I whipped up a crude JSON-style parsing function. Besides, its always fun making your file extensions.

So in test.anim we see the following:

{
  'music' : ,
  'nomusic' : 0,
  'backimg' : ,

  'trans' : ,
}

The first { } is always the ‘metadata’ tags for the animatic file. Music is which sound you want to play when the entire animatic starts up, and this will play until the end of the animatic. NoMusic will shut off any CD music playing in the background ( don’t worry, it’ll resume the stopped music when the animatic finishes). BackImg is if you want 1 background image to be rendered beneath all subsequent image frames. Finally, Trans is for ‘transparency’, setting the global alpha value of the animatic during playback. These values are then stored in a 1-dimensional string array labelled simply named ANM_META_DATA. Once the metadata is loaded the text parser expects frame data to come next. Frames are defined by { } as well, and there’s no true limit, for the sake of brevity I imposed a 20 frame max (do you really need moar?).


{
  'image' : gfx/hud/target_box.png,
   'pos' : 0.79 0.225,
   'size' : 0.05 0.05,
   'sound' : sound/anim/t1m4_lineb.ogg,
   'text' : ,
   'alpha' : 0.85,
   'color' : 1 0 0,
   'text_color' : 0 0 0,
   'time' : 3,
}

Image is which image you want this frame to display, and you can set it to null / empty.

Pos is ‘screen position’ important: this is done in percentage of screen to make sure that the coordinates are screen-size agnostic.

Size is the size of the image. important: this is done in percentage of screen to make sure that the coordinates are screen-size agnostic.

Sound is the sound file you want to play on this frame. Its non-looping, and is not clipped by any sound on the next frame, so playback overlap is a risk here.

Text is any text you want rendered, I have this hardcoded to be rendered at the bottom of the screen and centered.

Alpha is the transparency of the frame.

Color is the color-tint you want to apply to the frame image and text. RGB values are in vector format between 0.001 - 1.0 for each color.

Text_color same as Color but overrides the color for the text.

Time how many seconds to render the frame for.


In addition to these tags, the code automatically does a fade-in/fade-out effect for each frame but I’m still on the fence if this is necessary or not. When the text parser reads these tags into the code, the frame reference number is used as the primary key for a series of arrays. I’m not particularly happy with this solution but I’ve chalked it up to the roughness of Quake C more than anything else….

string ANM_FRAME_IMG[20];
string ANM_FRAME_SND[20];
float ANM_FRAME_TIM[20];
vector ANM_FRAME_POS[20];
vector ANM_FRAME_SIZE[20];
string ANM_FRAME_MSG[20];
float ANM_FRAME_ALPHA[20];
vector ANM_FRAME_COLOR[20];
vector ANM_FRAME_TXT_CLR[20];


Did I mention that any sort of collections are non-existent in Quake C?

The outcome for all this is a simple but working system for achieving cutscenes and character transmissions for battleMETAL. There’s still some refinement to be had mostly due to a lack of use and testing of the code, but as it stands I’ve tested that the code works at all.

Monday, January 21, 2019

battleMETAL - And Yet, Somehow it all works - part 2 - HUD

Heads up!?

Now that we’re sort of familiar with CSQC and what its about, we can take a look at the HUD for battleMETAL. There were 2 distinct phases to arriving at the HUD code that is now in the game. The first step was expanding the GUI functions I had created for the in-game menus that we saw in last the article. battleMETAL’s DNA is western mech sims of the 90’s, and that genre of games loved its HUD mechanics.


a HUD from Earthsiege 2


It seems in hindsight that mastery of reading a mech’s HUD was integral to the overall gameplay experience of a mech sim, given how much information is being sent to the player. One of my opinions as to why mech games lost market share over time was their built-in complexity that scares away newcomers, much like how Starcraft II today.


My first attempt at a HUD system was to take the generic GUI functions I had made, and craft a single HUD for each mech. The entry point for the HUD system was and is a single function call in CSQC_update_view(). I pass the player unit type to the client, and if that unit type is ‘mech’ then it runs the hud_frame() function. In the first system, I created HUDs as entity objects in CSQC, believing it to be the easiest way to hold data and functions for each HUD. You can kinda see the madness here on this github link to the battleMETAL project. Each HUD object implemented the same ‘soft’ interface of each hud element function, along with an initializer function that setup each object.


Now, in a more modern engine or code base, this isn’t exactly a bad idea. A proper class object for each HUD would be a fine way of rendering the HUD. Over in Quake C land, I was not so fortunate - there’s only 1 object close to being a class, the entity, and we all know now they’re not really the same. This attempt ended up repeating a ton of boiler plate code, and overall was too unwieldy. Tacitly, I had made some out-of-scope assumptions about what the HUD should be able to accomplish as a system. It was good that I coded it in a direction towards a robust UI system, one should always code for universality. I realized later that the HUD didn’t need this universality, it didn’t need an open system for rendering layered UI graphics...it needed to be bespoke. Quake C’s limitations have a tendency to hone your design instincts to one-off solutions for each module.


The next step in coding the HUD system was to disabuse myself of trying to make an object-based, layered HUD system. Rather, I decided to reorient the design to being built up from simple functions. I realized that each mech HUD doesn’t really have unique functionality that would ever really differ from another HUD. That is to say, mech HUDs all contain the same information where the only differences are slight variety in presentation and position on-screen of the HUD elements.

It took about a weekend, but I refactored every single piece of HUD code. Rebuilt from the original pieces, I ended up with unique functions for specific pieces of the HUD. A few examples to explain what I’m getting at:

hud_renderEnergyMeter()


Each only deals with rendering a single type of HUD component. The method arguments for each also varies only by the information that each component needs for rendering. The responsibility for drawing the total HUD then shifts up to the main HUD function. This main function is named for the mech that it is supposed to go to, and I used a switch-case statement to determine which HUD is supposed to be drawn. When the player enters their mech, the server sends the mech’s id number to the client, and the switch-case statement selects the function by mech id.


Therefore, any given HUD main function becomes a short list of HUD component functions, the only important data that matters is the on-screen location of the HUD elements and the player data. This approach even allows a little bit of flexibility. To make more unique HUD elements, the code can either encapsulate the component in just the desired HUD or add it to the HUD function library which would then allow any HUD to use it if desired. I applied this principle at least once with the renderWeapon functions.



hud_renderWeapon1


hud_renderWeapon2


Both functions take the same information but render this information in a slightly different way. We can see that each weapon is rendered atomically this way which then also allows the designer to use both styles in the same HUD. In keeping with the modular approach, this entire set of code is only called by a single entry function renderHUDFrame() which keeps coupling between the main functionality and the HUD system loose. This reduces headaches in adding new features to either system, or when changing large pieces of either system. I had a decent amount of fun bringing the HUD system to life for battleMETAL, and I think the code reflects it. Adding new HUDs is straightforward and maintainable while troubleshooting existing HUDs wont outright break too much else.

Monday, December 31, 2018

battleMETAL - Why that was a bad idea, a terrible idea - Part 6 - Game Logic

A series of events;
 
    An important part of any game is level design and the game play loop of the level. One of the reasons I chose Quake / Darkplaces is because of how mod-friendly the map making process is...and how well documented it is. Back in my high school days, before learning to code, I had dabbled with making maps for Quake II. iD Tech games all generally used a tool called GTKRadiant for level creation, this was an all-in-one map maker for their games. The tool allowed users to created the full 3D spaces of a Quake level, place map objects like weapons, monsters, and player start zones. It also is where the logic of a map was created. These logic map objects were under sections called trigger_ and func_. They are responsible for making doors that move, elevators, changing maps, etc.


    There’s an old joke about iD games using the map design called a ‘monster closet.’ A monster closet is a part of the map where, behind a seemingly normal piece of wall, a monster or two is just sitting there. When the player gets close, or triggers a specific event, the wall opens up surprising the player and dropping monsters on them. This is a joke because if you look at the wall, it doesn’t look like it should logically have any space behind it and what exactly were the monsters doing behind the wall? Taking a smoke break?


    For this article, let’s focus on the how of the monster closet. The user in GTKRadiant would create a space behind the wall. They would place monster entities into that space. Next they’d turn the ‘normal’ wall piece into a door. The door, like the monsters, is another entity. Rather than relying on a specified model though, the door entity uses the map geometry its assigned as its model. Then the map designer would create another map object; trigger_once, point it to the ‘wall’. The Quake C would then say, “when the player entity touches trigger_once, open the door.” In this regard, we can say that the map file holds a lot of the game state and logic. 


    I believed that at least for map design and creation, Quake was a good move. Creating custom entities that the editor can place was fairly straightforward. GTKRadiant uses a text file to define all the possible map entities that can be placed before compiling the map into a format that Quake can read. By adding my own battleMETAL objects to this text file, I found it was easier to create maps specifically for battleMETAL - including the really cool aspects like Nav Points and Objectives ( we’ll get to those in a bit). Unlike AI which I covered previously, the map logic schema for Quake is surprisingly flexible. The map editor GTKRadiant uses a series of ‘definition’ files containing text, usually called entities.def. This file contains the definitions for entities to be placed on the map.


    The definitions must link to function names in the Quake C code. For example, the definition for an enemy AI looks like this in the .def file:
   
/*QUAKED unit_human_mech_sniper (1 0 0) (-14 -14 -20) (14 14 20) <spawn flags>
        <description text here>
    */
   
    The “QUAKED” is the head tag for an entity definition, the next piece is the function name “unit_human_mech_sniper” which should be defined in the Quake C code exactly the same wording. From what I can tell, the map compiles the entities and converts the function name either to a reference or compares the function name to all the functions in the code to find a match. Once the game finds the right function, it creates an entity and then calls this function on that entity. Whatever code is written in unit_human_mech_sniper is then run immediately.

    The next series of arguments are as follows: color in GTKRadiant, and the bounding box size. The color is for color coding the entity in the map editor, making it easier to tell entities apart from each other. As for bounding box size, that is also shown in the editor, but will also be passed to the engine when the entity is spawned. Quake C code can override the bounding boxes if it is needed. Spawnflags are an important piece of data for both the editor and the engine. Flags are a data storage concept used in general coding. They hold a series of “yes or no” sets in a single variable usually by using binary math. For our purposes here, every entity has a spawnflags field which can set up certain “yes or no” choices when the entity is created. The exact wording is up to the coder, so one entity might have DROP_TO_FLOOR for a spawnflag while another has START_INACTIVE.  The map editor will render these as checkboxes.


    Finally there’s a the descriptor section, it is here that normal text will be rendered in the map editor but has no relation to code in the game. This section is for any relevant info about creating, placing , and using a map entity. Altogether this system is fairly easy to understand and extend for modding. Debugging is nice as well, if engine can’t parse the entity from the map, it simply removes the entry and logs the result into the console.


    Now that we have context for the maps, we can do quick overview of the game logic itself. Every gameplay instance in Quake takes place on one of these maps files. The map is loaded up when the server switches to the desired map file. In Quake C this before  the Main() function is run, the main is the entry function for the Quake C. StartFrame() is any code you want to run before the engine runs all other code in that slice of server time. From here the game instance if open-ended, where the ‘end’ of a map can be determined in a few different ways. Vanilla Quake used round timers, kill counts, and map entities to end a game instance and load the next map. For battleMETAL I needed something a bit more sophisticated, seeing as how the game is descended from different DNA.


    battleMETAL is inspired by mech sims, in which part of the simulation was of more authentic military scenarios. This meant that the player is given a set number of ‘objectives’ to achieve before the scenario is ended. The objectives sometimes were destroying things, but other times it was just visiting a location on the map or protecting a base of buildings from an attacking enemy. So, to achieve a similar setup as I created some custom map objects - the Objective, and the Nav Point. I also extended the game engine to load in a text file called a “mission file.” The world map entity would have a variable that pointed to a specified mission file that was loaded to the player’s view when they connect to a map. The code I wrote also sends a unique objective ID for each objective on the map. This is linked to a list of objectives in the mission file. Together, they communicate objectives to the player both during the briefing and game play.


    Of all the things I found to be difficult with battleMETAL, this was surprisingly not one of those things. The configuration of GTKRadiant is fairly well documented and extending the functionality of making maps for my specific game turned out to not be a lovecraftian nightmare, unlike other parts of the project….well except for those 3D terrain meshes…<sigh>.

Wednesday, December 12, 2018

battleMETAL - Why that was a bad idea, a terrible idea - Part 5 - AI deux

Ah, that army...well played.

    Now that we have some context about how the Quake AI code works, we can look into why it was a no-go for battleMETAL. The first hiccup is how battleMETAL builds its AI entities. Like the player, AI entities are built using the same factory pattern code. The entity is actually a bunch of entities strung together - things like torsos, arms….legs. battleMETAL units are not animated as a complete distinct model. Because they are collection of parts, each part has its own animation. This breaks the original Quake C architecture and its reliance on the frame macros (as was explained in the last post).


    The unit piece with the most animation was the leg entity for mechs. However, the animations for the legs are not authoritative to other entity states. Therefore most code hooked up to leg frame animations is not decisive, but rather cosmetic; reacting to game events as they happen. Just having this one attached entity threw off the need for using Quake frame macros. A different solution was needed, and that was using a state machine. State machines are abstract computer designs that describe a series of ‘states’ for an arbitrary object. An AI object is a good candidate for state machines, where the state in the state machine could be a set of behavior or actions that the AI performs.


    Mind you, this was after a few other attempts to split the difference with Quake’s original AI implementation. The original code also had a set of generic AI behaviors that most monsters would invoke in about the same sequence. There existed functions like ai_walk, ai_run and so on, these were called on a per-frame basis and packed into a frame macro for the monsters. Additionally, other functions were used by the AI during gameplay to assist in calculating attacks, spotting the player, and moving around defined node entities.


    All of this existing functionality was put off to the side, to be reworked into the new AI design. Using a state machine, I broke down almost all the possible actions that an AI could take into 2 categories - states, and actions. I then declared a state to be a collection of actions. I credit my cousin Eamonn with the idea of making actions were atomic as possible ie each action as a function call would only do 1 specific thing. For example, the walk state would be the following actions:
    Scan for enemy
    Move to patrol node

 
And that would be just the walk state. If the AI spotted a valid target in Scan For Enemy, the the AI would transition to the Run state. The code marks each state with an integer, 0 = Walk, 1 = Run. Each entity then has a series of member function pointers to each state like mech.st_walk(). When the AI is created, the code tells the AI which version of of st_walk to use. In the case of mech units, they’d be assigned the mech_walk() function. 


    Then, the AI keeps track of which state it is in by having a variable called .attack_state, when the AI executes its code every frame it looks up which function to run by using its state variable. Once this paradigm was implemented, I took the idea to the next step - organizing collections of states into ‘behaviors’ or ‘unit types’. Tanks and Mechs would clearly need their own sets of state functions because of how different these units are. Using this approach I found it was easy to implement even more unit types like turrets and non-combat vehicles. Each behavior set, although using the same list of actions has their own logical flow for states, and changing the state they are on. The result is a fairly flexible and open-ended design for adding AI and its behavior.


    There are still some limits due to the foundation of this code being on Quake. A big one is AI movement. The Quake C uses an engine function to actually execute the movement of bots and no physics operations are carried out, this results in stiff movement of bots that doesn’t really look natural. This also results in bots running more slowly during gameplay, their per-frame updates are less because of how proportionally expensive it is for the game engine to move bots. In the end I’m ok with the outcome of the AI, despite its limitations I was able to add a few diverse unit types to the game. This diversity helped make the game more fun and engaging to play.


Monday, December 10, 2018

battleMETAL - Why that was a bad idea, a terrible idea - Part 4 - AI

Oh yeah? You and what army?
Another tarpit that consumed many months of dev time during this project was the AI. Quake was never known for its AI, which was only ever serviceable. The problem was thinking that the AI was extensible for the needs of battleMETAL. Quake AI is good enough for ‘basic’ FPS games. The code available allows for AI that can follow defined paths, attack and ‘fight’ with the player, and some limited hunting routines. All of this code is laid out in a few generic functions available to all AI and any monster-specific code is defined in that monster’s code file. Quake monsters are fairly capable of engaging the player in the tighter, more confined environments that Quake uses (big surprise). However I estimated that expanding level geometry size would not have had a great impact on the AI code, not realizing just how tightly engineered the AI code was.

The first wrinkle encountered was one part of how the AI code is implemented in Quake itself. Quake C functionality sits atop the C code of the engine, with limited access to engine-level code (by design). This equates to the Quake C doing the bulk of the AI work here. This means that AI execution is a tad slower due to the nature of Quake C being a parsed language versus running straight C code. I accepted these limitations due to lack of foresight and with the mistaken assumption that I could reuse a lot of the original code.

First hurdle turned out to be understanding the way the AI code was written. For example, in the m_grunt we see the following function:

                   void() army_stand1 [ $stand1, army_stand2 ] { ai_stand(); };

For me, that looked really wierd, and I had not encountered similar code in the project other than some simple animations for sprites. Let’s break this one down; what we’re looking at is a code macro. Code macros are like syntactic sugar, which is lingo for ‘shorthand’. Much like other abstract languages, such as math, have shorthand notations when writing large segments and code can also have shorthand. Most of the code shorthand is usually already baked into the language syntax itself, such as var foo = a_value. This is shorthand for the computer assigning the value a_value to the variable foo.

But what if you found yourself writing the same code many times, and would rather reduce this code to a simpler syntax? This is where macros come in. Macros can be user-defined, and customized according to the needs of the programmer. For Quake C, iD created the macro I mentioned earlier, for use with animations being synchronized to game code. Originally the animation frame rate was tied to the game’s frame rate, mostly because computing power was very limited back in 1996. It didn’t matter that the animation was tied to the game’s update rate because usually that update rate didn’t surpass 20FPS on most systems. The second part was tying game code to the animations themselves; what should happen when the Frame X of the animation is played?

So looking back to the example macro, this is what it means

        Army_stand1 is a function definition.

         The [ and ] are part of the Frame macro, this has 2 arguments, the frame number of the current frame and the next function to go to.

         $stand1 is the frame number of the first frame of the ‘stand’ animation.

         Army_stand2 is the name of the function that should be executed next after this function( army_stand1 )
 

        The { and } then define the function body for army_stand1, what code should be executed on this frame.

When dealing with models that have dozens of frames and multiple sets of animations, this is a clever way of organizing the overall flow of the entity’s animation and code. Knowing the schema for the macro, you can now read through a model’s game logic quickly and easily. There is a cost however.

The macro is more rigid than writing the code out yourself every time. What I mean by this is that the frame macro is laser-focused on solving the animation / code synchronization issue. What happens when I don’t need any code to run on a frame of animation? I still need to define the macro for that frame. This creates a problem at-scale when model animations start reaching the dozens or hundreds of frames. That was the main reason why I, once understanding what the macro does, ditched it in favor of my own approach.


I won’t go into super detail about all the attempts to bring the AI to life - there were 9 major runs of work to arrive at the solution I went with, spread across 3 distinct solutions. The 3rd solution was what ended up working, and even then I have ways it could have been improved. This topic will continue into at least a second post so I can discuss the working solution...

Monday, August 27, 2018

battleMETAL - Why that was a bad idea, a terrible idea - Part 3 - Collision Systems

About those multi-part models


Collision systems a core part of any video game engine. From the first version of Pong up to the latest games on any platform, these systems are responsible for processing impacts between game objects in the game space. In general, like most computer code, collision systems have to be built at some point because a computer does not intrinsically know when two ‘objects’ have hit each other. The complexity of these systems can vary wildly depending on how detailed the game wants to get for collisions and how complicated the game itself is. Quake’s collision system is fairly simple for a 3D FPS.

The collision system for Quake starts with a series of boxes, or specifically, axis-aligned bounding boxes (AABB). Woah there’s some jargon, AABB simply means that the collision model for a game object is a box (technically a rectangle because box proportions can be altered). The axis-aligned part means that this bounding box does not rotate. The model can change angles all it wants, but in the eyes of the collision system, it never rotates - this is an important distinction.

Here we see Quake Guy and his AABB. Whenever Quake Guy hits another entity, or is hit by entity, the game doesn’t check the Quake Guy model for this collision. Instead, the game sees if Quake Guy’s AABB was contacted; which is mathematically simpler and therefore a faster calculation. The downsides to simple AABB is the lack of detail in collision detection, this can be best seen when Quake Guy is standing on a staircase or slope. Notice how only a few corners of the AABB are touching the ground?

Let’s make one quick jump back to the previous post about models, specifically the models that make up a mech in battleMETAL. These entities use a move type called movetype_follow which tells the game to always keep the entity’s center as an offset from a code-defined center in game space. There’s one important detail here, entities with movetype_follow cannot have a collision AABB. As a restriction, this exists because the use-case for movetype_follow is for cosmetic models put on the parent entity - weapons, clothes, etc. For battleMETAL, this means that the various mech parts that are seen on-screen don’t actually have a link to the collision system. Hm, but battleMETAL requires a feature where mechs various parts can be blown off the mech.

The solution implemented is a bit obtuse to manages to satisfy the requirement and still work. The player seen on screen is a heavy composite of several code pieces and models. To start, the player doesn’t actually have a model bound to its entity structure. Rather, the visual components - the mech piece models - are all separate entities using the movetype_follow functionality to appear in the correct location during gameplay. From the perspective of the collisions system however, these pieces are ‘wrapped’ inside the player’s main AABB. When a player is struck by a weapon, the following is executed in the code:

  1. Determine the gamespace location of the hit, this is a 3D vector of X Y Z
  2. Query the gamespace location of every mech piece that the player-being-hit owns.
  3. Find the closest mech piece to the hit origin.
  4. Closest mech piece becomes the area that is ‘hit’.
More modern game engines can execute what is called Per-Poly collision where the gamepsace location of a collision between objects can be focused on the smallest parts of the models themselves. Quake is much more primitive as we have seen. The solution that battleMETAL uses is not the most precise for players, but works surprisingly well in-action. The majority of hits against a target are applied to the correct piece of the mech (if the target is a mech) and battleMETAL uses this multi-part collision detection only in very limited cases. Every weapon strike is a short loop through all the mech parts of the mech target, which can get computationally expensive if a lot of mechs are on screen.

There are some quirks to the written algorithm as well.

  1. Ignores the volume of each model piece on the mech
  2. An imprecision thats hard to detect
  3. Effects on mech design
In the end, this was deemed acceptable if it allowed players to destroy components of mech models in the game. There are several other problems with the collision system being so primitive - such as interactions between moving objects and the terrain models. The 4-point ground detection code can get a bit cagey when trying to detect collisions with a terrain piece that changes its slope too quickly- something like a really bumpy road or rocky area. This necessitated keeping terrain features more simple in their mesh complexity.

Tuesday, August 14, 2018

battleMETAL - Why that was a bad idea, a terrible idea - Part 2 - Model Mishaps

Compromises were made
Models are a good enough place to start about things that went awry. The most complicated models so far in battleMETAL are the star units themselves, the metals. The game requires that certain game units have multiple hit locations that can be destroyed before the entire unit is killed. In the case of the mechs, the locations are the center torso, left and right torsos, left and right arms, and the legs. 5 locations total for every mech unit. To better communicate damage to players, it was decided that arms and torsos should be ‘blown off’ when the health of those areas reach zero. This translates to each mech piece its own disconnect mesh, like a lego piece.

Most FPS games don’t deal with complex vehicles, they are scaled to people-sized players and monsters fighting. The models for each of this units is usually 1 solid, animated mesh. Despite complexity of the model, the fact that model is 1 contiguous piece of geometry makes working with them fairly easy. Having five sub-models that make up one complete mech model gets heavy very quickly. It increases the number of files per game unit, makes coding for game units a bit more complex. More modern game engines can handle this complication using techniques like bone-based modeling. Quake was made slightly before skeletal animation became an industry standard. Half-Life is credited with bringing skeletal animation to the mainstream and Half-Life’s engine is a heavily modified version of the Quake 1 engine.

Darkplaces does allow for skeletal animation but it comes with some severe catches. The quake c code for Darkplaces can utilize bones but only on the client-side. Now why is this a problem? I think I mentioned client-side prediction as an issue in previous posts. The snag with this approach is that the bones are only rendered on the client’s side of the game code. If the bones are only on the client then the location in game-space of those bones becomes an issue due to discrepancies between server and client game states. If Darkplaces came with out-of-the-box client-side prediction for programmers to work with, then this might be less technical debt. As it stands, client-side prediction was left up to the individual coder for some...reason...and not every programmer is up to the task of solving a such a complex issue.

The other possible option for skeletal animation is found in the Quake 3 model format called md3. This model format was made for Quake 3, itself a multiplayer-centric, fast-paced, arena FPS from late 1999. Quake 3 also made an attempt to fix client-side issues of skeletal animation but John Carmack went about it in his own unique way. MD3 models can be given little ‘tag’ triangles (a triangle being made up of 3 vertices in the model). Each ‘tag’ would then be given a unique name within the model for later reference. The technical debt of this approach is how tags are organized. When making a model, the tags have to be made, pointing in the desired direction of orientation for the mesh that will be attached there. The tags themselves are not saved when the model is exported to md3, thus any subsequent work on the mesh will require remaking the tags in their specific location.

For Quake 3 models that only ever had 1 or 2 tags per model, the ‘tag’ method was an ok solution. battleMETAL however, breaks this through complexity of the models in the game. The solution I settled on isn’t exactly performant for multiplayer gaming (thankfully battleMETAL is more a single-player game), but it does work. Remember how every model is an entity in quake c? Entities can be given specified ‘movement’ types to reflect, in the engine, how the entity is supposed to move. Player entities have MOVETYPE_WALK which is for handling player movement and physics. Darkplaces expands this functionality by adding a new MOVETYPE_FOLLOW. This movement mode is for objects that cannot collide with anything, and is for entities that, well, follow another entity.

General use-case for movetype_follow in the context of Quake is things like, having the gun model that a player is holding reflected externally by having a gun entity set to movetype_follow. Using this, battleMETAL treats all mech model pieces as separate entities with the movetype_follow. The locations of the pieces are set in relation to the controlling player’s origin point. In this way, the requirement of having hit locations, and visible damage have been satisfied without resorting to time consuming or costly programming quirks. The code uses the Factory Pattern to turn a mech data file into a mech, including the construction of the model component entities.

battleMETAL was able to use some animation for the mech models in the end. The leg models for every mech are animated in the model creation program and exported to the md3 format when animations are complete. The quake c code then controls the playback of those animations. Although this means animations are comparatively ‘stiff’ when put next to modern games, they are sufficient for the project.

Monday, August 6, 2018

battleMETAL - Quake/Darkplaces was a bad idea - Part 1

This was a terrible idea

Late again with the blog post, ach, about 2 weeks out from moving to a new location. This part is a quick overview detailing all the fun to be had pointing out why Quake / Darkplaces was a terrible choice. A feeling that I had upon reaching spring 2018, having been working on battleMETAL since July 2016, was that of exhaustion. Any strengths that the Darkplaces engine might have offered turned out to not really offset the Technical Debt that was incurred by the requirements of the game.

A great example of this situation was level creation. For original Quake, the best way to make levels is to use one of a few tools specifically dedicated to this task. Tools like GTKRadiant, QUARK, or TrenchBroom. These tools facilitate level creation by providing a means for designers to create the terrain for a level, place objects such as lights, monsters, player start point, select textures for the levels, and modify lighting. The level building tool then compiles all this information into a .bsp file that Quake loads when entering a level. Mapping for Quake is a well documented process, the advantage of being a popular and easy-to-mod game from 1996. There was just one big hitch in the process - Quake can’t really do outdoor terrain, cue the record-scratch sound.

See, in 1996 - and even well into the late 90’s and very early 2000’s, outdoor terrain was hard to achieve. Computer power was more limited despite the advances since 1993’s DooM game. Many games achieved a feeling of outdoor space through camera tricks, data storage techniques, or even art / design aesthetics. The method that Quake uses for creating level terrain is called Binary Space Partition or BSP. We’re not going to go deep into that particular set of computer programming, rather here’s the gist: the game (Quake) creates walls, floors, doors, ceilings, ramps, stairs, etc out of chunks of 3d space called brushes. When the map is compiled, the compiler takes the interior space of these brushes and compiles them into one large mesh of vertices. For computers in the 90’s, this was a level format that was easy to render without killing frame rate.

The Quake level design tools allow the user to create, reshape, change size, change textures of all brushes in a map. However, as we’ve seen with these old 90’s games, the brush-based system of level making results in very….chunky world aesthetics. There are ways to generate ‘realistic’ terrain with this brush method, but it results in map files that take several minutes or hours to compile. For battleMETAL a work around was found, by treating the terrain mesh as 3d model like any other 3d model, the game now had a way for realistic terrain. The sacrifice was that this terrain model does not show up in the map editors available, leaving the user to guess where to place other objects on the map. By requiring more accurate terrain models for the game, battleMETAL lost the ability to leverage Quake level makers which is a large trade-off indeed. This next part of the blog series will be just as the subtitle describes; why that (choosing Quake / Darkplaces ) was a bad idea.

Monday, July 16, 2018

battleMETAL - Why Quake / Darkplaces - Part 7 - Input Layer

It's a bit more tricky than one thinks 
One very important aspect of game engines is reading player input. Kind of hard to play a game if a player can’t actually control anything, right? Avoiding a more technical conversation of engine frames, processor cycles, and the like, game input is important because it needs to be timely. When picking game engines to use, input configuration is also a specific feature to compare. Quake has a few points towards itself in the area of game input, making configuration and custom behavior easy to create and maintain. Starting at the top level, Quake has multiple ways for a player to assign keys and bindings for behavior.

The 2 primary ways to change key bindings are using a console command ‘bind X key <action>’ and the second is modifying the .cfg config file. Using the bind console command, a player can change key bindings at anytime during gameplay. This is great for players and programmers. The config file is just another format of console commands, rather then being used in the console, the commands are loaded from a text file on start up or whenever the user enters the ‘reloadconfig’ command.

In the Quake C code, there exists functions to get the action bound to any given key and a way to programmatically set a keybinding. This allows the programmer to determine what keys are being used, and how, as well as make easier the task of custom key actions. Both the server and the client (remember Client-side Quake C?) can intercept key button presses for even more custom code or to consume a key press so that it does not go on to the other end of the network. A fun extension to the Quake engine provided by Darkplaces are key bindings for controllers and joysticks. Controllers and Joystick bindings aren’t a priority but if possible to implement, it’d be a welcome addition to the types of players of battleMETAL.

Custom, game-specific action code can read for player input within 2 ‘channels’ so-to-speak of input. There are impulse commands, and button commands. Impulse commands are used for one-off key presses. The engine can only read 1 impulse per frame - wait, that sounds limited? Ah ha, says the game engine, consider this: Although the game engine can only read 1 impulse per frame, the entire engine is running anywhere between 60 frames per second or higher on modern systems. This frame rate is high enough where the player will never notice that the engine is only reading 1 impulse per frame! Impulses are stored in a variable on the player’s entity under the name ‘impulse’. The engine runs the function, ImpulseCommands() on every player on the every frame. The programmer puts their custom code into that function, allowing for custom code to be bound to specific impulses.
 

The second piece are ‘buttons.’ These are slightly different than impulses. The state of a Button is not cleared every frame, whereas impulses are. So if the player is holding down the ‘forward’ button, then every frame knows the player is holding down that button. This difference is important because Buttons are used for constant-on commands such as moving forward, or jumping, or attacking. Another key difference between Buttons and impulses is that there are only a set number of ‘Buttons’ that the engine can recognize. These aren’t buttons on your keyboard, but a specific set of buttons numbered 0 to 9 internal to the engine. Quake generally uses ‘button0’ as the ‘fire weapon’ button, and this is generally bound to Mouse1 - your left mouse button.
 

In summary, Quake and by extension Darkplaces, have a tight handle on player input. Allowing for both player and programmer a level of flexibility not seen in most other engines. Out of the box, Quake’s input system is understandable by both player and programmer. Of all the parts of battleMETAL that had to be coded, the input system was one of the easiest. 

And this wraps of the 'Why' of using Quake/Darkplaces, in the next segment we will see why that was a really bad idea in the long run!

Monday, June 25, 2018

battleMETAL - Why Quake / Darkplaces - Part 5 - Network Layer

Connecting for long distance mech mayhem
 

I will try to keep out of the deep end for this portion of the blog series. I forgot that these sections aren’t meant to be a detailed breakdown of the Quake engine or the Darkplaces source port. Rather, these posts are laying out the battleMETAL project’s discovery and assumptions before the work of battleMETAL truly began. In that spirit, these posts should be fairly short and mostly general about tech, code, architecture, etc.

At the time I was deciding whether or not to roll forward with Quake / Darkplaces for an engine, the concept of having multiplayer stood out. A mech game with some dedicated multiplayer would surely be a great game to try, and maybe even with friends. Quake’s network architecture, despite being a tad dated, is fairly robust. DooM’s network layer was peer-to-peer, where game-state was sent around to every player on the server; Quake’s networking is client-server. A main server of the game is started, and then all players connect to the server as clients. This is a server-authoritative design, where game-state is held on the server and then sent to clients. While this scales more nicely than DooM’s peer-to-peer system, the architecture wanders into sticky issues like client-side prediction and lag.

Deep diving into game networking aside, Quake had the feature set that overlapped with battleMETAL’s requirements nicely. Out-of-the-box, Quake allows any players to create their own servers, configure those servers (map, game mode, number of players, certain game rules, etc) and Quake has functionality for server-browsing. Although the menu system for Quake was rudimentary (even by late 90’s standards) it demonstrated that this functionality could be accessed by modders and programmers using custom code. The end result is customized server-browsing menus and features that have been added to battleMETAL.

In game code, Darkplaces also had mapped out functions for processing player input, data transmission between client and server, and functionality for fully customizing the player’s client-side view. Now that said, the exact knowledge for implementing these features was a bit more esoteric, but we will get into that later. Knowing that the network layer was securely placed in the engine code, vs the game code that battleMETAL would be using, Quake really had an attractive feature set for networked gameplay. One benefit of using a source port like Darkplaces is that there have been some key updates to the original Quakes network code. A little bit of client-side prediction which alleviates latency between server and client. Also increases the packet size, allowing more data to be transferred between client and server (after all, network speeds have increased since 1996.)

Further on in this series we will see that some of these initial assumptions might have been a tad generous or very much off the mark of what was actually useable. For now, let’s stick with the bright and rosy details that Quake was setup to be a multiplayer game and that therefore battleMETAL would be inheriting this functionality with little trouble.

Monday, June 18, 2018

battleMETAL - Why Quake / Darkplaces - Part 4 - The Game Loop



...and looping through it
The core of any game is the ‘main loop’. There’s a reason why we developers throw around the word ‘engine’ when talking about games. The best analogy I use is a car engine. The car burns fuel, which moves pistons that turn a camshaft. That camshaft then turns a belt called the ‘timing’ belt. The timing belt is the clock of the car engine. A game engine is very close to this. The base code is setup to run through a series of functions in a specific order, and there’s a ‘timing belt’ that keeps internal time. In Quake that ‘timing belt’ is a variable nicely called time.

Entities, remember those little guys from earlier? also form the only true ‘object’ for the Quake C language. Quake C is a cut-down version of the C language, which is powerful but does not do ‘objects’ very well. Quake C gets around this but ever so slightly. There is only 1 type of entity and all extensions to that entity are given to every entity. What this means is, if there is a custom value, such as ‘weapon type’ for an entity, every entity will now have this variable regardless if it used by that entity. This design paradigm is a blessing and a curse. The blessing is that it means creating customized entities is as simple as just assigning values to the programmer’s desired variables. The curse is that it means the code will bloat-up really fast, leaving hundreds of entities with unused values.

When a player launches a game of Quake, after going through the menu system, and launching into a desired map; the engine creates a list of entities. Almost every object on-screen is an entity. Quake organizes its entities into a list, or more specifically in-code, an array. The wonky aspects begin here. This array of entities has a fixed limit, ie how many total entities the engine can have ever. Original Quake can only handle about 640….Darkplaces however upped this cap to 32,768. Quite an improvement, eh? However there’s still a quirk remaining. The array of entities in Quake is more like a slot-system. Each of those 32,000 places in the array is a slot with a number. When the code wants to create a new entity, it finds the next available slot to place the entity...based on where the slot counter is. It is never a guarantee that the next entity the code creates is right after the current entity the code is on.

This also kinda creates a problem with removing entities. Quake never technically ‘removes’ an entity from the array. Instead, it ‘zeroes out’ the entity’s variables, removing things such as any model assigned to it, and other variables. This is was an intentional design by iD Software. Although there’s a difficulty in determining if any given entity is ‘empty’, it allows the system to ruthlessly clean up ‘unused’ entities to keep system cost down. Darkplaces keeps this paradigm in place, allowing for a fast run through of all the entities in the main array.

Entities can be invoked with the spawn() which returns an entity, usually the code will load this entity into a variable for modification: local entity foo = spawn(). From there, the programmer then must assign the variables they want to go into the entity. If the programmer wants the entity to do something in the future, they would assign a .think() function. A think() function is any code that is executed every time that entity is activated in the entity array. There are several other ‘template’ functions that can be used for various parts of entity behavior. Want to have custom code run when one entity touches another? Give that entity a .touch() function.

A programmercan also create their own child functions for the parent entity, such as entity.thisFunction(). And thanks to the code being C-like; this specific function can be whichever function the coder wants to point to. This allows for neat tricks where a set of entities can have the same function, .thisFunction() but for each entity, the actual function is completely different, like this example:

  Entity A

     .myFunction() = fireWeapon_Type_1()

  Entity B

     .myFunction() = fireWeapon_Type_2()


So when the code calls .myFunction(), if the entity is A, then fireWeapon_Type_1 is called. There’s a bunch of other C language quirks that are leveraged in Quake C, but that’s drilling down into programming language design.
Despite some of the limitations with the programming language, I liked the straightforward approach to the code design. 


I figured I could apply higher level code principles to the Quake C language to get around some of its limitations - a fine example is using the Factory Pattern for entity creation. I don’t need to rewrite the same entity customization when making, say, a missile entity. Instead, I can invoke a makeMissile function that does it all for me. Entity cleanup is a bit trickier, and checking if an entity is truly ‘empty’ or ‘null’ (in code parlance) remains a problem that has to be accounted for. Writing interfaces was sort of out of the question, but I think the entity object in Quake C qualifies as an abstract class which is super helpful.

Monday, June 11, 2018

battleMETAL - Why Quake / Darkplaces - Part 3 - 3D Rendering



Putting Stuff on-screen...


I understand that a lot of this content might be dry for readers who aren’t big into the nuts and bolts of game programming, and I’m sure that this probably doesn’t go deep enough for people who do. That said, I’m almost through this topic and I feel it needs to be typed out for context and for my own reference.

Keeping with the theme of why Quake/Darkplaces, this post will shift over to the rendering aspects of Darkplaces that merited looking into the engine. Darkplaces increases the types of 3D model file formats that can be used in-game, expanding from Quake 1’s thoroughly ancient (by 2016) .mdl format. Darkplaces can use .obj, .md2, .md3, .ase 3D model formats and their higher poly-counts. battleMETAL was never going to be a graphical powerhouse that could challenge modern games. I had the desire to make a game where graphics were clean enough that players could understand what they were looking at without being able to make super lush models.

The .md3 model format suited the project’s needs fairly well. MD3 is Quake III’s model format, which is from 1999. It's interesting to see what only 3 years of difference between Quake 1’s MDL and Quake III’s MD3 makes. MD3 can hold more detail, can something like 256 skins for a model file, and can have different textures for different models in the file. The MD3 format’s animation data is vertex based instead of bone based. MD3 was design by John Carmack for Quake III, so its footprint over a game network is incredibly low. Animations aren’t exactly a high priority (as we’ll see when I break down how I made the mech models).

Quake’s paradigm for adding models to objects is also fairly simple. Almost every object you see on the screen, in-code, is a thing called an entity. An entity is an abstract concept in game design, being a root-object of sorts from which all other objects inherit from. An entity in Quake can only ever have 1 model associated with it, which is given to the entity with the code command setmodel(). Once an entity has a model, there is functionality to affect the rendering of that model. Code can make the model partially visible, or invisible, glow with color, etc. So even if an entity has a mode, the game coder can dictate when that model should be visible. Another benefit is that an entity’s model can be changed quickly to something else entirely or removed if needed as well.

Now why does this matter? From where I sit, Quake lets the designer manage the game’s assets in their own way. Modern game design dictates that assets must be loaded into the entire development kit of the specific engine that the developer is using. There are benefits to this top-down approach, such as uniformity of design process when maintaining a project across a larger team. It also allows developers to move from project to project with familiarity of the tools. However, for battleMETAL and its one-man-army of me, I didn’t need such a heavy-handed approach. Quake allows me to manage assets as needed, adding or removing models at the code level, or even updated models in the file folders.


The last set of positives for Darkplaces is that the engine also provides tools for realtime lighting and shadows. Older game engines generally do not have this feature due to system limitations. ‘Realtime’ lighting is shorthand for saying lighting is dynamic as objects move around the game world as well as lights turning on and off. It also means lighting is more realistically represented when being projected from a source. Lighting in 3D computer graphics is its own Lovecraft-ian world that I won’t get into here, and you can find better explanations of it elsewhere. For Darkplaces, Levels can have light entities, and entities themselves can give off light. For battleMETAL, the Darkplaces lighting system is ‘good enough,’ providing enough detail to look good and allow for design aesthetics but also performant and manageable.

A neat tool that Darkplaces has is the ability to modify lights in a game level in real time using a series of built in commands. These changes are then saved to a specific file, ‘<map name>.rtlight’ which the game will load every time that map is opened. The advantage of this tool is no need to have to rebuild or recompile the map to test different lighting styles. The file is a plain text file with coordinate data, which also means the file can be copied and reapplied to other levels, or the same level. An example would be having a map transition from day to night, or a building’s lights turn on after being initially off.

The looser, bottom-up design of Darkplaces features put less emphasis on mastering a specific development environment and more on designer-based preference for their own tools. Engines like Unreal and Unity have lengthy tutorials for the various all-in-one tools they provide. For someone who doesn’t know these tools, the time required to learn them inhibits game design and the iterative testing of the project. Eventually I will give these a shot because they have their own pros and cons, but for now, I didn’t want to feel like I was fighting the tools too much….and yes we will see how I would eat this words in a buffet of hubris over this series of posts.

Monday, May 21, 2018

battleMETAL - The Dare - Part 2


(this one is a bit lengthy, some paragraphs are skippable :P)
How it all started
I had been doing the exercise of designing games since 2008, but those early efforts were plagued with poor planning and lack of knowledge. I give 2012 as a starting point because that was the year I sat down and said “I am going to make a video game.” No, this game wasn’t battleMETAL. This was Project Redshift, what became known as the game Zond. Zond is a top-down, Asteroids-like game built in Java. The player commanded any one of the classic Space Race era spacecraft in combat missions. I never really finished the game and you can learn more about it by going here.

Zond fizzled out for various reasons, both technical and non-technical, however I learned a lot about the process of game making. The project wasn’t large enough to bury a one-man team, but its features challenged me as a programmer. It also gave me a crash course into core game code design and some of the paradigms used commonly in game coding. After Zond, I cast about for a few years making other attempts at video games, most work was exploratory and mired in technical debt. It wasn’t until 2016 that I thought about making another ‘serious’ go of ‘it’.

When you are the Devil’s Advocate in a case against yourself

So here comes 2016, and I’ve been wondering what game to make. A long time ago I remember reading a quote that has stuck with me - “Make the games you want to play.” I can’t remember who said it, but it has become a mantra that I believe in. Make the games, you want to play, ignore the gaming zeitgeist and make what you want. What games do I like to play? Simulators….but not just any….mech simulators. Ever since I fired up Mechwarrior 2 back in the ancient past of 1996, Mech Games have been one of my all time favorite genres of game. There’s nothing cooler than stomping forward, deflecting a hail storm of cannon fire, in your armored leviathan. An avatar of war, a walking tank. To fight another mech is to engage in a knightly duel of old, or like two Aces in WW1 biplanes, or two prize fighters in boxing. I love the motifs of mech games, the themes, the spectacle. Sadly by 2016 the gaming zeitgeist had declared mech games to be very dead.

See, by 2016, Simulators are a kinda dead genre. No large company is really making them, for whatever reasons (I could get into that but its heavily opinionated salt). My only options as a gamer to get some mech action in the style of Mechwarrior was really only Mechwarrior: Online and that in my opinion is super depressing. Mechwarrior: Online is a pale shadow of what mech games can be and what Mechwarrior games used to be. That previous sentence was opinion, if you weren’t sure, but it's important to know that because that leads into the impetus for making battleMETAL. So I ask myself - what is stopping me from finally making a mech game? I’ve been kicking around ideas for a few years, along with talks with close friends about concepts and design for mech games.

The initial stopping point was technology. I tried working with Unreal 4 but at the time in 2015, I found the UI overwhelming for a single developer to really get traction. I thought about Unity but it looked like I’d face the same uphill challenges as Unreal, at the time, remember - hindsight is everything. Thinking about my options, I dredged up an idea from the past - what about Quake? To make a side story short, I was familiar with making Quake II maps back in 2002 / 2003 or so, and had read about a few source ports of the Quake 1 engine, namely Darkplaces. Quake 1 also had its own specific C-style language that was purpose built for modding Quake.

It sounded like Darkplaces was a good ‘my first 3d engine’ to really dive into, it felt approachable. Functionality was literal, not hidden behind splashy UI. Here’s an example: to get texture effects like light-reflection and bump mapping? Simply add 2 files - <your texture>_bump.tga, <your texture>_gloss.tga. Darkplaces had a built-in file system for loading and caching game files. Rendering was secondary, I’m not a graphical artist by trade so I was prepared to make a game that looked ‘ok’. Another plus for Darkplaces was that it had a network-layer built into the game as well as entity management. There’s a power to game engines where you can just start coding the fun stuff...and a danger.

Then came July 4th, 2016. Having just finished a barbecue with friends at our apartment, I sat down to do some really dumb tests with Darkplaces. In one evening, I replaced the Player model with an old mech model I had made in 2015, and I changed the weapon model to a cockpit mesh I made sometime in 2013 / 2014. Here were the results:

 These screen shots are Quake but I replaced the Player model with my own mech model and replaced the First-Person gun model with a cockpit.


And that was one evening! My head exploded with ideas, drawn in with a “well this doesn’t look so hard” mentality. As we’ll see over the next 1.5 years, that was the definition of short-term success hiding long-term pain. Eventually I fought through the ‘necro-tech’, realizing just how obsolete a game engine Darkplaces really is. Through it all, it still is one hell of an adventure into game design. battleMETAL is a case where I played Devil’s Advocate for myself, why not a mech game right now? Why not just ‘get it done? The mantra I’d end up using throughout the entire project as the months wore on became:


Perfect, is the enemy of good.

Monday, May 14, 2018

battleMETAL - The Dare - Part 1

Who am I
To be super brief - just some 30-something guy from New England, in the United States.

To be a bit more specific? Programmer, artist, historian, painter of miniatures, and game designer. I’m not going to try and recount my life story here but merely try and give some context to the person behind this entire project.

The threads winding their way through my life to get to this point would be longer than socially bearable to recount. Two events in my childhood, looking back now, I think, are what would end up altering my career path. These are more clear in hindsight, about 20 years later, but at the time and even into college I didn’t really think about it.

The first event was joining the ‘Computer Club’ in 5th grade. Now to be clear, this was a normal public school, in 1997, in more-rural-esque Connecticut. So, if you expected a guided experience with some old sweat coder….you are quite wrong. It was run by a well-meaning if a bit misguided teacher who wasn’t so great with computers. The club was mostly about using macs and the program called Hyperstudio to create super simple ‘programs.’ hilarious outdated link. Most of the things we made in that club could be charitably called ‘interactive Power Point presentations.’

The roots of the idea was there, though. The program showed how to create menus, do limited animation and sound. It was a ‘first’ step towards coding and computer game design for me if there ever was one. Up until this point I thought I wanted to go into Marine Biology.

I’ve wanted to be a game designer / maker since 8th grade. The reason I can remember it so clearly is because of the TI-86 graphing calculator ( https://en.wikipedia.org/wiki/TI-86 ). Every student at the time was required to get one in my school as we entered 8th grade in 2000. One of the discoveries we, students, made was that not only was the TI-86 super handy actual math...but it could also run games. In 2000, seven years before iPhones and ubiquitous mobile devices, being able to play games anywhere was still a bit of a luxury. Sure the GameBoy was around but you couldn’t exactly play that in class without getting it taken away at some point. The TI-86? Perfect camouflage.

By 9th grade, the start of high school, I had found you could indeed code your own games onto the calculator...and into the internet of the early 2000’s I went. I scrounged around for tutorials, how-to’s, anything I could get my hands on. I read up on printing characters to the screen using an X/Y coordinate system. I learned about interpreting user input, and the keycode number for every key on the calculator. I played around with writing simple little menus for my games.

 Early attempts were clones of projects I found online, printing out reams of code on paper for later reference. Although many of these projects existed on my family computer (I did buy the pc / calculator cable so that I could code on the pc), sadly all were lost in the subsequent years of hard drive failures. After this point, things were reliably on track for me through high school and into college.

Those early habits of scouring any and all knowledge for help in my own efforts has stayed with me. In a quirky twist, these skills also ignited a love of History that still burns today. As to how this relates to battleMETAL? In the coming posts you will see how the self-confidence of that young programmer would be challenged and reforged. How learning to sift through and collate disparate fonts of information would help in completing a (so-far) arduous task.

Wednesday, May 9, 2018

The cold rise from sleep...

5 years and a what feels like a life time...

I'm going to attempt to start this blog up again mostly to document the video game battleMETAL that I have been working since mid-2016. I had planned on doing a retrospective when the game was finished but decided a weekly or bi-weekly blog would make the task less daunting. 

Posts are going to range from general discussion of the development of battleMETAL to focusing on specific challenges or features of the project. 

<fumbles in pocket, pulling out wrinkled napkin>
 
I do have a rough outline for this series of posts, and I'll try to stay on-script as best I can. I will also try to make sure the posts happen in a regular fashion, as blog posting is not a habit of mine and for the longest time I personally felt it took time away from working on the actual project.


Some of these posts will also get a bit technical when discussing in-depth topics, if you find yourself struggling - feel free to skip that post, but I do encourage trying to muddle through.


The Dare 
  •     Who am I
  •     How it all started - when you are the Devil’s Advocate in a case against yourself

Why Quake / Darkplaces

  •      Reasons for
  •      The Devil you thought you knew well enough
  •      File management
  •      File type loading
  •      3d renderer
  •      Game loop
  •      Networking layer
  •      Menu layer
  •      Input layer

Why that was a bad idea, a terrible idea

  •      Everything discovered
  •      Map pipeline
  •      Model issues
  •      AI
  •      Collison system
  •      Game Logic

And Yet, somehow, it works

  •      Sanity is preserved in the console logging functions
  •      Eventual map pipeline
  •      Game Data systems
  •      Flexible, but built in systems
  •      Mech model implementation
  •      AI implementation 1
  •      AI implementation 2
  •      The Mech Hud
  •      Hud Impl 1
    •    Sorta generic, entity based
  •      Hud Impl 2
    •     Generics, generics, generics
  •      The CSQC Menu System
  •      Overall design
  •      Briefing menu
  •      Text wrap
  •      Mech hangar / arming
  •      Deployment menu
  •      The Menu.dat
  •      Entities, callbacks, swtich cases, textfields, dragon drops
  •      File Loading and folder layout
  •      Animatic System