Showing posts with label Game Development. Show all posts
Showing posts with label Game Development. Show all posts

March 20, 2019

Game Mods Moving To Patreon

Starting next month, I'm going to be able to block time out for dedicated work on game mods, and starting in September, I'm going to have a dedicated room just for my game development work.

Work on new mods is going to move to my Patreon.

The Terraria mod I'm going to be working on is codenamed TSA (Terraria Server Assistant).  Basically, I'm going to be using the Mono.Cecil work that I spearheaded with the Terraria client to expose a lot more information through the server and extend its command support.

The Quake 1/2 work I'm going to be working on involves making mods easier to make in this day and age.

The Hollow Knight mod I'm working on is a rather simple tombstone mod so you'll know every place that you died during your entire run.

The Left 4 Dead 2 work I'm doing involves finishing up some of the unfinished mutations in ShackMutations.

There's no reason to join or donate unless you want early access as all of the mods will be released for free.

November 8, 2017

Game Jam Entry

For the first time in quite a while, I finished a game jam entry this last weekend.

It's not the most polished or the most balanced, but the important thing is that I actually released it.

I've lost count of the number of half-baked and half-finished prototypes I have lying around, so it was important to me that I actually release something this time.

If you get a chance, please try it and all of the entries to the Shacknews Jam.  So far, I'm partial to "Run Don Run."

I'm going to be out of town from Thursday through Sunday this week.

August 11, 2017

Minor Update

Rejoined the IGDA.

Now have a Unity Plus license for the next year.

Still working on shit.

July 13, 2017

GMTK Game Jam Tomorrow

There's a Game Maker's Toolkit Game Jam starting tomorrow and I'm going to try to livestream my attempt at participating.

I'm going to set up a simple test stream tonight and if all goes well, I'll post the stream links in a new post tomorrow night.  I'll be participating from 6pm PDT Friday through 6pm PDT on Sunday and will put my final bits up on itch.io.

January 16, 2017

Blue Asterisk Instead Of Red Cross

I noticed this article on Kotaku about the developers of Prison Architect running into trouble when they used the Red Cross to denote health.  We encountered something similar back when we were developing SiN Episodes: Emergence.

If you play SiN Ep, you may notice that all of the health containers have a blue asterisk and have the initialism F.T.R.C. emblazoned on them (standing for the Freeport Trauma Recovery Center).

What you may not know was that this was a response to me forwarding an article from GameIndustry.biz to management (link to summary), and the artists deciding to put in a response that a) lined up with the color of the healing spray, b) was not in any way able to be mistaken for a red cross or red crescent, and c) was a subtle way of putting in an initialism for "Fuck The Red Cross."

December 7, 2016

Ten Years Out

I left the games industry in December 2006.

I've looked back, and while there are things I miss, I won't be going back into games full-time until I can go back on my own terms.

April 10, 2016

Almost Done...

While I was working on adding high resolution support to Gnomoria, I decided that the obfuscated nature of the binary gave me a new opportunity: generalizing the hack.

I'm modifying RomTerraria so that you can add a basic version of the RomTerraria resolution hack to any XNA executable.

Mind you, I'm a bit stuck for time until I get Electric Eye out the door to all of my partners at my day job, but I'm hoping to have it done in the next week or two.  I'm using Dust: An Elysian Tail and Gnomoria as my guinea pigs.

April 5, 2015

Handling Quake 1 .map Files (Part 1)

Now, let's say you want to handle Quake 1 .map files.  Perhaps you want to do the project I'm doing: porting Quake to other engines.  Perhaps you want to use Quake 1-compatible level editors for your MonoGame or three.js projects.  Who knows?  Code for this series will be provided in C# for easy integration into tools and content pipelines.

First, let's look at what an entry in a .map file looks like.

{
 {
  ( x1 y1 z1 ) ( x2 y2 z2 ) ( x3 y3 z3 ) TEXTURENAME xofs yofs rotation xscale yscale
  ...
 }
 "key" "value" // Optional comment
}

Each entry in a .map file is enclosed in curly braces to encompass an entity.

Each entity can contain zero to many brushes.  Each brush is enclosed in curly braces.

Each brush must be convex can contain four to many faces.  (Why four?  Think of a three-sided pyramid and the base.)

Each face includes three vertices to define the plane, shown above as (x1,y1,z1) through (x3,y3,z3), a texture name, and all the information needed to calculate the texture coordinates for each final vertex.  Vertices are in clockwise order.  Most of the time, these vertices are the first three vertices of that face, but not always.  They're just there to define the plane.

Each entity can also contain one to many key/value pairs.  Each entity will have one key named "classname" which tells you what other key/value pairs you should expect.

If you find a classname of "worldspawn" in the entity, this will be all of your static geometry.  You can use this information to heavily optimize this information for rendering or other work: do texture batching, visibility calculations, collision calculations, etc.

While you can have comments in your .map files, you probably won't see them.

If you think about it, this gives you a good way to handle save game separation as well.  When you are saving your game, iterate through your world and serialize out the information for any entity that isn't worldspawn.  When you are loading the saved game, you can load only the worldspawn entity, then overlay your other entity information from your save game.

Now that we have that information, we know what we need to parse the .map file.  Here's a functioning map parser.  It fills a Map object with Entities that can contain key/value pairs and Brush objects containing Faces.

http://www.romsteady.net/quake1/Quake1Map-ParserOnly.zip

Next time, we'll turn this information to a polygon soup.

March 30, 2015

The Failures Of Binary Formats In Development

One thing I've wanted to do for the last few weeks is dive back into game development.  While I was back at Amazon, I could do game dev work that I had grandfathered in, but I couldn't technically do any new game dev work.  Fortunately, Netflix lets me do pretty much whatever I want outside the office, provided it isn't creating a new video streaming service.

With that said, I needed a solid project to drive me forward.  I had licenses for Unreal Engine 4, Unity 4/5, and Leadwerks 3.x, tons of assets I had been collecting and licensing over the last few years, and some larger projects in mind, but I wanted something small and contained...something where I could spend a week or two working on the project and have something done.  I wanted something completable.

While I was browsing through my assets looking for a little inspiration, I found quake_map_source.zip.  Basically, John Romero had released the original .map files for Quake v1.06 back in 2006.  I started remembering back when Tenebrae was released, people were going in and manually placing lights to try to get the effects, and here I am with the source files.  Why not see if I could get Quake maps functioning in these other engines?  And thus, a project was born.  I wouldn't be able to release a full project because that would virally taint the engines with the GPL, but I could release code and tools to let people recreate it themselves.

I decided to start with Leadwerks.  I had backed the v3 engine on Kickstarter, and Josh had been nice enough to release the runtime code to the Map class loader at my request.

The Leadwerks map class is a binary chunked format.  The first 32 bytes of the file include a magic number to identify it as a Leadwerks scene file (SCEN), a version number, and then offsets to where you will find each chunk.  Dealing with a chunked file is fairly easy to do:

  1. Serialize each chunk to an internal buffer
  2. Write out an empty directory chunk up front
  3. For each buffer that you want to write out...
    1. Store the current file location
    2. Write out the chunk
  4. Once you're done writing out all the chunks, seek back to the beginning and write the offsets for each chunk into the file

The first item that needed to be done was to write out an empty map file.  If I can't write out an empty file, I don't stand a chance of getting the rest done.

There are two chunks that are critical to working with a Leadwerks file: the String Table and the Map Info chunks.  The String Table is where strings are supposed to be stored, and they'll be referred to by IDs within the Leadwerks file.  The Map Info table has general information about the map.

Let's start with the Map Info chunk.  If you have a Leadwerks license, you can download the file in the above-linked post and follow along.  Please be aware that after a lot of headaches, I rolled back to map version 22 for what I was going to try to export.

Starting on line 352, it wants the number and resolution of light maps.  That's easy...I don't have any.  Two ints out.

Line 408 wants ambient lighting.  Four 1.0f values.

Line 413 wants a map size.  Inspection of the UI shows valid values of 1024, 2048, and 4096.  1024 it is.

Line 414 wants gravity.  The UI shows a positive value, but the value is stored in the map file as a negative value, so -25 is serialized.

Line 424 looks like wasted space, and I just serialized out 0 and 0f depending on the field, but we'll come back to this.

Now for the comment on 438:
// This just uses the regular string commands, not the fancy string index system
If you look at an actual file, it means that it's going to try to read in an actual string here, terminated by a Chr(13)/Chr(10) line break.  Okay...ReadLine() is used for integrated text, ReadString() is used for string table data...got it.

The String Table chunk starts with a string count, and is then just a dump of null-terminated ASCII strings.

I also serialized out empty object tables, navigation mesh tables, and terrain info chunks.  The end result is a fairly simple, empty file.  If I load the empty file in the engine itself, it works fine.   However, if I load the empty file in the editor, the editor crashes with an access violation.

So what happened here?  Let's go back and look at that line 424 item.  The engine is throwing away this data, but the editor requires some specific stuff there.  While I'm not going to guess what the first two int values are, I think the next four groupings are data about the four viewports.

So in this case, we have editor data intermingled with runtime data.  That's a bit of a problem.  I'll have to think about the editor as well as the engine representation.

I understand the appeal of keeping a binary file for your worlds.  You can keep all of your dependencies in a single file or location.  You can have things in a ready-to-run format for your engine.  Speed of iteration (time from edit to gameplay) seems to drop dramatically.  There are major benefits.  However, there are large drawbacks.

First, maintenance. This map shows other issues with maintaining binary formats over a long time.  Look at line 443:
if (version > 22 && version < 25)
In other words, for only those versions, read in an integrated string, split it out, and apply the post f/x shaders there.  If this had been a text file, the key/value pair could have been easily ignored or converted out to a new format on save.

Second, corruption.  Let's say I've got a hefty map and as part of a save, a small portion gets corrupted.  If I have a text file, I can generally go in, find the problem area, and either figure out how to fix it or how to excise it so I can rebuild.  If a binary file gets corrupted...oh, well.

Some of you are thinking that any game developer worth his or her salt would be using source control, which leads to number three, source control.  Source control systems work best with text files.  Some, like Perforce, do a good job with handling binary diffing.  Others, like git, really dislike binary files.  Hell, even Unity has started offering a text format for its levels because of this.  It's in YAML, which is a pain to work with, but it works.

Fourth, extensibility.  There's nothing wrong with using a binary package or a bake for modules that you want to share out in order to keep all the dependencies in one place or to make it easy to handle module licensing, but when it comes to working with the core engine itself, allowing full import of scenes from text can be crucial.  When I initially asked for the map class to be released, I was working on some procedural content stuff.  I wanted to be able to create a single file that I could import that had lights, geometry, triggers, script hookups, etc.  You can import your geometry easily enough in most of these engines, provided you can export into a proper format (FBX, COLLADA, etc.), but can you import gameplay primitives just as easily?

When I get home tonight, I'm going to try to bring in the 424 chunk, and I'm going to try to get this Leadwerks file writer out as code for people, but this has really reinforced why any game dev work I do going forward is going to try to keep plain text files for my non-runtime representations of game primitives where appropriate.  I'd rather spend a little extra time baking for runtime and keep the flexibility it gives me.

Minor update, 6:13pm: After extracting the values from another map, it does look like those values are used for the editor.  After adding those values in, the editor no longer aborts out with an access violation.  It just quits silently.

January 24, 2015

Helper - Convert FPS Creator Models for Leadwerks Using Ultimate Unwrap 3D Pro

Just a quick post tonight.

I found this wonderful tutorial by Jesse B. Anderson on how to convert FPS Creator Classic models to work with Leadwerks Engine 3.x.

I have a copy of Ultimate Unwrap3D Pro 32-bit, so I thought I'd try to automate the process since UU3D doesn't have a batch mode.

This is an extremely early copy of the code for my automation.  YOU WILL NEED TO MODIFY THIS CODE FOR YOUR OWN ENVIRONMENT. THIS CODE IS NOT VERY STABLE.  THERE'S STILL A LOT OF WORK TO BE DONE.

That said, this code is managing to successfully convert FPSC meshes and animated models over, as well as create animation key files for import into Leadwerks 3.3.  To use it, modify the paths that are going to be converted/converted to in the source, launch UU3D, and let it go.  If you run it through the debugger, you can usually hit "Continue" when Windows Automation freaks out and it will continue.

A later version is going to import the models into Leadwerks and properly scale the models, but this may be useful for some people as is.

January 25, 2014

Classes Missing From Leadwerks Documentation

It looks like some classes/functions/methods are missing from the Leadwerks class documentation.  Some are likely due to the beta nature of things and others are just oversights, but here's a partial list...

NetworkDriver
- SetCurrent
- GetCurrent

Listener
- Create

Attractor
- GetAlphaMode
- Create
- SetAlphaMode
- SetRange
- GetRange
- SetForce
- GetForce

Buffer
- SetColorTexture
- Create
- GetCurrent
- GetWidth
- CountColorTextures
- Disable
- GetDepthTexture
- GetColorTexture
- SetColor
- SetDepthTexture
- GetHeight
- SetCurrent
- Enable
- SetMask
- Clear

Event

Sprite
- GetSize
- SetAngle
- Create
- SetSize

Component
- CallOutputs

January 18, 2014

Lua in Leadwerks #1: Settings, Action Maps

(Files here under CC-BY-NC-SA license can be downloaded here.  Root post for series can be found here.)

First, I wanted a central location for me to establish defaults for my games and a consistent way for user overrides to be saved and reloaded.  This is one possible solution.

The ZIP file above contains four files: RomSettings.lua, RomActionMap.lua, DefaultSettings.lua, and App.lua.  App.lua is the stock App.lua, just modified to show how to hook into the

My first thought was that I would use Lua 5.1's function environment features to safely deserialize a Settings object and then do a selective merge into my default settings, but that led to two small problems.  First, the function environment settings in Lua 5.1 are disabled in Leadwerks for Lua and will cause the app to exit immediately upon execution.  Second, the function environment features in Lua are being removed in Lua 5.2, so my scripts wouldn't be future-proof.

Leadwerks does expose two new functions that we can use, though: System:GetProperty and System:SetProperty.  These will allow you to save and load strings that get saved in a file in your AppData/Local/[gamename] folder on Windows.  However, they only allows you to save and load strings, which limit their usefulness.

To use the attached files, extract DefaultSettings.lua, RomSettings.lua, and RomActionMap.lua into your Scripts folder.  At the top of your App.lua file, add the following:
import "Scripts/RomSettings.lua"
import "Scripts/RomActionMap.lua"
At the top of your App:Start() function, add the following:

System:LoadSettings()

At the beginning of App:Loop(), replace the "end program" state with the following:

 --If window has been closed, end the program
 if self.window:Closed() or ActionMap:IsHit(Settings.ActionMap.QuitApp) then
  Settings:SaveSettings()
  return false
 end

After you run it and exit, go check out your [gamename].cfg file in your AppData/Local/[gamename] folder.

Now for a quick walkthrough on how everything works, starting with System:SaveSettings.

System:SaveSettings recursively walks through the Settings object. Since we can only save strings, but need to reinflate to the proper type, I serialize each type to a string and add a prefix so that when I am deserializing I can reinflate correctly.  If there is an array, I'll also create an "n" field so I know how many items there are.

System:LoadSettings acts a little differently.  It recursively walks through the DefaultSettings object and only tries to inflate settings that it knows about.

ActionMap was covered before.

To add/remove/change the default settings, just modify DefaultSettings.lua.  Those will get copied into the Settings global at the top of RomSettings.lua.

I'm going to start work on the replacement player object tomorrow.

January 17, 2014

Lua in Leadwerks #0: Tentative Feature List

This is the opening post for the list of items I want to code from scratch in Lua to work with Leadwerks 3.1 Indie Edition in no particular order.  As features get implemented, this post will be updated to have links to the implementation posts.  Each post will have the folders from the FromScratch project so you can use the code as you see fit provided you comply with the accompanying license.

Note that this is not a promise that all of this will be coded, just that it is my intention to do it if time and motivation permits me.
  • Input mapping (any input [mouse, keyboard, gamepad] to any function)
  • Load/save support
  • First person shooter controller
    • Movement and strafing
    • Aiming using the mouse
      • Invert Y-axis
      • Mouse Sensitivity
    • Jump
    • Crouch
    • Sprint (enhanced using FOV tricks)
    • Sneak (enhanced using FOV tricks)
    • Swim
    • Possess multiple weapons and switch between them
    • Camera decoupled from controller
    • Ladders
  • Weapons
    • Melee
    • Hitscan
    • Projectile
    • (potentiallly) Aim assist when using gamepad
  • Camera
    • Adjustable FOV (and demonstrate why high FOV can have a negative effect on visual fidelity)
    • Compatible with "render-to-texture" mods
  • HUD
    • Health
    • Ammo
    • Subtitles and/or closed captioning
    • Key tutorials
    • Viewport camera
  • Doors
    • All lockable/remote openable
    • Rotating
    • Sliding
  • Triggers
    • Activate once
      • On entry
      • On exit
    • Activate while in
  • Level transitions
    • Maintain health/ammo across maps
    • (Potentially) migrate items around you ala Half-Life
  • Menus
    • Buttons
    • Checkboxes
    • Radio Buttons
    • Sliders
    • (Potentially) text input
    • (Potentially) console/in-game debug log
  • Localization support
Work starts in a few hours.  Time for a good night's sleep.

Update 1/26:  Added viewport camera to HUD.
Update 2/8: Added ladders to FPS controller.

January 15, 2014

XNA is Dead. Boo. Long Live What?

I just got home from a little teeny tiny XNA meetup in Seattle that happened to coincide with Steam Dev Days.

It was kind of a weird experience.  The biggest takeaway for me is that, at least for Microsoft platforms, the likelihood of XNA coming back from the dead is almost nil.  For enterprise software development, .NET is king and has taken the place of Visual Basic 6, but for everything else, it's either JavaScript/HTML5 or C++.  I get the feeling that Microsoft backing Unity is more a "meh, Unity gets the basics right and nobody will know about how badly they fuck up the rest until they become advanced" move than an actual strategy.

The really sad thing is that unless Microsoft steps up, XNA may live long and prosper on almost every non-Microsoft platform in existence due to Monogame.  I overheard some NDA stuff that I won't go into, but I find it really funny that there are people who are chomping at the bit to pick up what Microsoft has thrown away here.

That said, I feel my time with XNA is pretty much gone.  My interest in XNA was always related to how it would democratize game development.  Game players who learn how to make games not only end up being better gamers, they also end up being better game community members.  They know how hard it is to do X, and their brief peek behind the curtain into the inner workings of how games work let them have a better appreciation for game developers and games themselves.

However, for a platform to inspire neophyte game developers, you need support, and XNA has lost it.  It's really hard for me to remain passionate about something that's fading away.  So, where am I going to focus my efforts now?

Lua.

Lua has been used in a lot of games as a scripting language.  All game and UI logic for both Amped and Amped 2 were written in Lua, and the only reason Lua didn't get any credit in the game or manuals is that their license at the time said it was optional and legal saw no reason to provide the credit.  In addition, two of the major low-cost game engine projects targeted at neophytes are shipping with Lua bindings: Leadwerks 3.1 and FPS Creator Reloaded.

However, a lot of the public scripts that are out there are, quite frankly, shit.  Even the little hacks I've published over the last few days are shit.  If I'm going to do this right, I'm going to have to go back to first principles.

Here is my plan.  Starting this weekend, I'm going to try to write a game from scratch against Leadwerks 3.1 Indie Edition.  My goal is to use absolutely none of the scripts that ship with the engine, though.  I'm going to start from nothing and move on from there.

This will do three things.  First, it will give a ground-up point of view of what it takes to build a game using Lua with lessons that can be applied to multiple game engines.  Second, it will help me better understand what it takes to be effective with Lua.  Third, it will help me get ready to better use an engine that I backed on Kickstarter before the C++ bindings

Hopefully, this works out well for everyone.  I'll still remain involved with .NET and XNA, but even more on the periphery than before, unfortunately.

January 12, 2014

Bind Multiple Inputs To An Action In Leadwerks Indie Edition

It is generally considered poor form to have key bindings buried in the middle of a class.  This code will let you keep your key and mouse bindings separate from your Leadwerks Lua classes, and also let you bind multiple inputs to a single action.

Create a new script in your Scripts folder named ActionMap.lua.  Add the following code:

ActionMap = {}
ActionMap.forward = { "W" }
ActionMap.back = { "S" }
ActionMap.left = { "A" }
ActionMap.right = { "D" }
ActionMap.fire = { 1 }
ActionMap.jump = { "Space" }
ActionMap.reload = { "R" }

ActionMap.use = { "E", 2 }
ActionMap.debugPhysics = { "P" }

function ActionMap:IsHit(action)
    local i=1
    local window=Window:GetCurrent()
    while action[i]~=nil do
        if (type(action[i]) == "string") then
            if window:KeyHit(Key[action[i]]) then
                return true
            end
        end
        if (type(action[i]) == "number") then
            if window:MouseHit(action[i]) then
                return true
            end
        end
        i=i+1
    end
    return false
end

function ActionMap:IsDown(action)
    local i=1
    local window=Window:GetCurrent()
    while action[i]~=nil do
        if (type(action[i]) == "string") then
            if window:KeyDown(Key[action[i]]) then
                return true
            end
        end
        if (type(action[i]) == "number") then
            if window:MouseDown(action[i]) then
                return true
            end
        end
        i=i+1
    end
    return false
end


Now open your FPSPlayer.lua folder.  At the top, add:

import "Scripts/ActionMap.lua"

Now search for the following code:

if window:KeyHit(Key.E) then

Change it to the following code:

if ActionMap:IsHit(ActionMap.use) then

Now run your game.  You'll notice you can still use "E" to trigger the Use method, but you can also right-click to trigger the Use method.

When you populate your ActionMaps, a number is a mouse button, and a string is one of the constants from the Key object.  Adding saving/loading key bindings to a file and allowing your customers to rebind their keys is left as an exercise for the reader.

Add Primitive HUD To Leadwerks Indie Edition

If you want to add a simple HUD to your Leadwerks Indie Edition game, here you go.

First, open FPSPlayer.lua.
At the top, under all the Script.* lines, add:

Script.hudFont = nil

Somewhere in Script:Start(), add:
self.hudFont = Font:Load("Fonts/Arial.ttf",20)

Scroll down to Script:PostRender(context).
After the code to add the blood splatter on the screen and before context:SetColor(1,1,1,1), add:

if self.hudFont~=nil then
    context:SetFont(self.hudFont)
    context:SetColor(1,1,1,1)
    local fontHeight = self.hudFont:GetHeight()
    local hudText = "Health: "..self.health
    local x = 0
    local y = context:GetHeight() - fontHeight
    context:DrawText(hudText, x, y)

    if self.weapon~=nil then
        hudText = "Ammo: "..self.weapon.clipammo.."/"..self.weapon.ammo
        x = context:GetWidth() - self.hudFont:GetTextWidth(hudText)
        context:DrawText(hudText, x, y)
    end

end

The only downside to this is that the debug text doesn't set its own font appropriately.  To fix that, open your App.lua file.  In App:Start(), add:

self.font = Font:Load("Fonts/Arial.ttf",10)

And in App:Loop, right after the "Render statistics" comment, add:

self.context:SetFont(self.font)

That should give you a HUD similar to the following:

January 11, 2014

Why Don't Games Have Input Remapping? (Public Draft)

(Note: This is a dry run for a YouTube series I'm planning on putting together and is a work in progress.)

A common complaint against PC games nowadays is a lack of proper input remapping in games.  We see triple-A games and indie games alike where being able to remap controls in a friendly manner is either not an available option, or is set up as a flow ("press Up, now press Down, now press Left, etc.") with no clue how many controls there are or any way of seeing what your controls are set to.

In this article, we're going to look at the history of input processing in video games and see how that history led us to where we are today, so let's start with...

Analog Input

In the beginning, there was Pong.  You had two potentiometers as controls and a button for reset/start.  Once a frame, the value of the potentiometer would be converted into a binary representation of its current resistance value via a process called ADC (analog to digital conversion).  That value would be stored in a certain memory location.  The code back then had to be really small, so it was hardcoded to look for that location.  Usually, the reset/start button just reset the entire device, and the device would start with the game "running" when you first turned it on.

Code back then was small and simple because it had to be. In pseudo-assembly...

LDX $PADDLE0

This would get compiled out to two bytes: the instruction to load the X register, and a byte offset from zero where the ADC value from the potentiometer was stored.  However, we then went to...

Atari Joysticks

The original Atari joysticks were amazing.  You had an eight-directional joystick and an action button per player! Wow, such progress.  Arcade games at the time used extremely similar code to what we'll be talking about here.

Joysticks were a set of switches under the hood.  When you pressed the action button or any of the four cardinal directions, a switch was closed.  If you pressed in a diagonal, two switches were closed.  For example, if you pressed diagonal up-left, the switches for up and left would be closed.

This will seem a bit weird, but if a switch was open, it was registered as a 1 in a bitmask.  If the joystick wasn't being pressed in a direction, it would return 15 (b1111).  Pressing up would mask off bit 0 and return 14 (b1110).  Down would mask off bit 1 and return 13 (b1101).  Left would mask off bit 2 and right would mask off bit 3.  The action button would be bound to a different memory address usually, and would return 1 if not pressed, and 0 if pressed.

So, if you wanted to see if a player was pressing in a certain direction, you'd do something similar in pseudo-assembly...

LDA b0001 // Load the accumulator with the bit we want to test
BIT $STICK0 // Check stick 1 to see if the bits in the accumulator are set
BNE $UP // Branch if the bit test failed (meaning the joystick was pressed)

This wouldn't take a lot of memory.  The load would be two bytes, the bit test would be three bytes, and the BNE call would be three bytes, for a total of eight bytes to check for up. Given that Atari 2600 games only had 4KB of space, you can see that input processing would take some space.

Now let's jump to...

Nintendo Gamepads


If you take a look at a Nintendo gamepad port, you may notice that it only has seven pins.  However, your Nintendo gamepad has eight buttons (the four directions, A, B, select and start).  Yes, this made input processing more difficult.  Long story short, every frame a "latch" signal would be sent to the controller asking for input data.  Once that "latch" signal was received, the developer would have to read from a certain memory location eight times in a row.  Each time, they'd get a single bit of data: either a 1 for a button being pressed, or a 0 for a button not being pressed.  Input processing for controller 1 would look like this pseudocode:

byte pad0 = 0;
for (int i = 0; i < 8; i++) {
  pad0 = pad0 * 2;
  pad0 &= (*paddlestate & 1);
}

This would get you all the inputs into the pad0 variable, and then you could bit-test.  SNES controllers worked the same way, except they had 16 bits in their controller entry (even though they only had twelve buttons).

A game like Super Mario Bros. (which was only 32KB), where only one player was playing at a time, could probably just switch the paddlestate pointer from controller 1 to controller 2 and keep the rest of the code the same.

One of the major benefits of Nintendo consoles was that most games had the same basic controls.  A jumped, B shot, etc.  There wasn't a requirement that it be this way (yet), but standard controls helped players quickly get going.

Now at this point, you're probably screaming, "Michael, you ignorant bint, this is all console crap. We already know that consoles are why we don't have decent controller mapping on console ports."  To which I reply, "No, that's not the only reason, and I'm getting to PC's in a moment, say...now."

DOS Games


Now, while controller inputs were handled in a fairly straightforward fashion on the consoles of the era, the PC was pretty much the wild west.  There was an optional joystick interface, but you couldn't rely on everyone having access to a joystick.  There was a controller everyone had to have, though...the PC keyboard.

When you'd press or release a key, an interrupt would fire and code in a keyboard interrupt handler would execute to handle the keypress.  Most applications would let the default keyboard interrupt handler do its work and just pass the final processed keypress along, but games would often jump in and "hook" the handler so they could do their own processing on key down and key up.

Each keypress would generate one or two scan codes.  For example, pressing the down arrow key would send hex 0xE0, 0x48. Releasing the down arrow key would send hex 0xD0.  If a game developer properly hooked the keyboard handler, they could keep a memory location up to date with whether or not a key they cared about was being pressed.

Most DOS games didn't offer keyboard remapping.  Since the size and shape of keyboards was pretty much standard, it was common for games to ship with keyboard overlays so you'd have a reminder of which key was which.  However, keyboards for other countries often caused problems.

Some games did offer keyboard remapping, but it was almost always through an external config utility.  Gamers would open a small utility that would let them pick the keys of their choice, and it would save the key down/key up codes from that press to a config file.  The game would load that config file and use that data in its keyboard hook, and the game, rather than check the input directly, would check an internal data structure to see if an input was set.  You'd end up with code like this in your keyboard hook...

struct Input {
  bool Left;
  bool Right;
  bool Fire;
...
}

Input newInput = prevInput;
newInput.Left = (scanCode == LeftUp ? false : (scanCode == LeftDown ? true : newInput.Left));
...

This would allow people to compare previous inputs to new input and act accordingly.  Other developers moved to an input event system.

vector<InputEvent> events;

if (scanCode == LeftUp) events.push_back (InputEvent_LeftUp);
...

The guys who had moved to event-based input were in great position when it came to moving to...

Windows Games

Coming soon...
- Lots of variation in controllers for PC at this point, but no standards
- Success of Quake makes in-game keyboard rebinding popular
- DirectInput, Sidewinder Joystick and MechWarrior 2 bring about a joystick renaissance
- Microsoft focus on gaming and purchasing of game developers leads to a positive feedback loop of features for DirectX
- Input event mapping built into DirectInput
- Rise of USB, elimination of dedicated gamepad port
- XInput, the PC gamepad renaissance
- Death of DirectInput and the near-death of the joystick

December 22, 2013

C++ 11 and Types

I've been trying to ramp up on all the language changes as part of C++ 11, and have been trying to figure out how to do something similar to XNA's Content.Load<T> as part of it, and I'm a bit stymied so far.  Let me explain.

XNA's ContentManager has a ton of features that seem like they'd work wonderfully in C++'s RAII world.  When you call .Load<T>, it first checks to see if the content has already been loaded through this particular ContentManager.  If it has, you get the cached copy back.  Otherwise, it tries to load the file, instantiates the proper type loader, caches the loaded object, then returns a reference to the object.  When ContentManager is disposed of, it handles cleaning up all of its cached objects for you.  Plus, I can keep multiple ContentManagers around: one for "common" items (characters, UX elements, etc.), and one per "level" (level-specific textures and geometry).  That way, you just dispose the level-specific content manager and start a new one up for a new level.  This pattern just screams RAII to me.  The gotcha is that each ContentManager can house multiple types.

Now at least at the moment, I'm at a loss for how to do this in a type-safe, RAII friendly manner in C++.  It's easy if I create a ContentManager per type of content to load into it (ContentManager<Texture2D>, ContentManager<LevelData>, ContentManager<BlahBlahBlah>, etc.), but then I lose the ease of working with a single object.  I could add a strongly typed reference for each type into ContentManager (ContentManager.LoadTexture2D, ContentManager.LoadLevelData, etc.), but then I lose loose coupling.  I could just keep a hash_map<string, void*> and force dynamic_cast to be used on load, but then I lose RAII cleanup of each subobject.

I'm sure there is a graceful solution to this that I just haven't found yet, but it's a fun problem space to explore.

Minor update: This weekend has taught me that I have much more to learn about the wonderful world of shared_ptr<T>.  The last major C++ codebase I worked in was a barely C++'d C codebase, so my mental model of C++ is still skewed horribly.

November 30, 2013

FIX: Missing { in modes text file

Problem:

You are working on script mods for Left 4 Dead 2 and when you are loading your mod, you keep getting an error about a missing open curly brace.  You've checked the file and everything appears to be lining up.

Solution:

Valve does a lot of things right with the Source engine.  Handling byte-order markers at the beginning of scripts is not one of them.  Open a command prompt, browse to your script, and use the "more" command to output your script to the command line.  What you are looking for is three garbage characters at the beginning of your script.


If you see those garbage bytes, congratulations, you've got an easy problem to solve.

Download and install Notepad++.  Open your script.  Go to the Encoding menu.  Change the encoding to either "Encode in ANSI" or "Encode in UTF-8 without BOM."  Save your script.

November 29, 2013

Games and Tools on Steam using .NET

Some of you may know that I have a near unhealthy Steam library, and I decided to spend a little time trying to figure out how many games on Steam are using the .NET Framework. I know most games are developed using native C/C++, and thanks to the popularity of Minecraft there's a growing Java contingent (like Delver and 3079), but I'll always have a soft spot for .NET.

This list is only games that use .NET in some respect.  Some games install .NET but don't appear to use it (like Batman: Arkham Origins).  Unity games are called out if they use Mono either instead of or in addition to native code libraries for logic.

This list isn't definitive, so if you know of other games on Steam that are using .NET or if I've put something on this list that shouldn't be here, please let me know by posting in the comments.

Title of Game (Game Framework/Technology)
  • Adventures of Shuggy (XNA 4.0)
  • AI War: Fleet Command (Unity)
  • Ancients of Ooga (Windows Forms for settings app only)
  • Apogee Throwback Pack (WPF for launcher only)
  • Atom Zombie Smasher (Tao.OpenGL)
  • Bastion (XNA 3.1)
  • Borderlands 2 (WPF for launcher only.  Has XNA 4.0 linked, but doesn't appear to use it)
  • Breath of Death VII (XNA 4.0)
  • Cthulhu Saves the World (XNA 4.0)
  • Cubemen (Unity)
  • Cubemen 2 (Unity)
  • Dead Pixels (XNA 4.0)
  • DLC Quest (XNA 4.0)
  • Dust: An Elysian Tail (XNA 4.0) 
  • Fable 3 (SlimDX for video options applet only)
  • Far Cry 3 (Windows Forms for Editor) 
  • FEZ (MonoGame) 
  • GunCraft (XNA? Need to validate)
  • Hammerwatch (OpenTK)
  • Lucidity (XNA 3.1)
  • Magicka (XNA 3.1)
  • Outlast (Unreal Engine...appears to just be C++/CLI managed hooks for debugging and editor wireup)
  • Penny Arcade's On The Rain-Slick Precipice of Darkness, Episode 3 (XNA 4.0)
  • Penny Arcade's On The Rain-Slick Precipice of Darkness, Episode 4 (XNA 4.0)
  • Rogue Legacy (XNA 4.0)
  • Sol Survivor (XNA 3.1)
  • Space Engineers (SharpDX)
  • Space Hulk (Unity)
  • Terraria (XNA 4.0)
  • The Witcher Enhanced Edition Digital Comic (Unity) 
  • The Witcher 2 (C++/CLI, COM interop to handle registration, password recovery, etc.)
Title of Tool (Portion using .NET)
  • Axis Game Factory (Unity)
  • GameMaker (Asset compiler, development web server) 
  • Music Creator 6 Touch (Fault reporter)
[Update 11/30] Added FEZ, Music Creator 6 Touch, Adventures of Shuggy, DLC Quest, Fable 3, Apogee Throwback Pack, Ancients of Ooga, Space Hulk, The Witcher Enhanced Edition, The Witcher 2.

[Update 1/16] Added GunCraft and Axis Game Factory.