Lessons learned by being The Worst Game Developer

Posted: October 27th, 2014 | Author: | Filed under: Art, Programming, Video Games | Comments Off

I’m writing a video game. It is called Pebble, and in Pebble, there is a pebble. You contemplate the pebble. I haven’t decided if there is going to be music or not, but there will be a pebble, in a featureless grey expanse, and you can contemplate it.

Just thinking about writing this game has brought me some interesting realizations. I doubt I’m the first one to have them, but it was neat to see how they all fit together.

The first realization is just a recap of things I already knew about developing software: “You’re going to throw the first one away” and “Do the simplest thing that could possibly work”.

When I first came up with the idea for Pebble, it was as a tech demo for Tree, which is similar (There is a tree, you contemplate it), but more complicated, in that a tree is larger. I was going to use level-of-detail (LoD) rendering to support real-time generative zoom from birds-eye to bugs-eye views, store seeds so that the generated versions didn’t change between runs, etc. I read a bunch of papers on the topics, and saw that it was all very complex. I also hadn’t written anything, despite having read a lot of papers and learned a bit.

Eventually, I realized that if I had to load everything I needed to know into my head to write this game, first, I wouldn’t get around to writing it, and second, my head would explode.

Instead of either of those things, I’m writing the simplest bit of code that will draw something on my screen. The first version will draw a polygon, the second version will rotate it, and the third version will texture it. I’m going to have two code streams, one written using openFrameworks and one written using Polycode, so I can decide which of those libraries I’d rather use.

Once both libraries are through three versions, I’ll have the simplest thing that could possibly work, and I’ll throw the other one away.

Another revelation I had is that I don’t really know what pebbles look like. I mean, I have a general idea, but to render a pebble, a general idea doesn’t cut it. It doesn’t capture the variety of surface types that different kinds of weathering can cause, the colors of all the different rocks, and so forth. The reality of pebbles is way more complicated than the idea of pebbles

My girlfriend and I went out on a beach on Cape Cod, Massachusetts, and looked at pebbles. Cape Cod is a terminal moraine, so the rocks there were pushed by glaciers from everywhere north of Cape Cod, and there are loads of different kinds of pebbles there.

This has two effects on my thinking about the design of Pebble, and of video games in general. The first is that the stone surface generation algorithim should be the simplest thing that could possibly work. The second is that AAA games in their current form are doomed.

AAA games have a huge amount of their budget dedicated to resources, such as the textures and designs of the characters. Because the current marketing push in video games is visual, each game is supposed to have better and better graphics than those before it, or people will mock it and it will loose sales. However, this is an infinite pit. Any game world is a map, a less-detailed reperesentation that conveys an impression of a more detailed real world. With real maps, the real world is assumed to also exist, but in games it doesn’t. You run around in Libery City in Grand Theft Auto, but “you” don’t “run” “around”. By pressing buttons, you cause the appearance of motion in a simulated person within a simulated, restricted world. The better the simulation gets, the more resources it requires. In real-world NYC, if you go to Battery Park, you can pick up gravel and throw it in the harbor. In the analogous unplaces in GTA, the ground is a perfect solid, smooth and impenetrable. In order to create a more perfect simulation, there would have to be simulated pebbles, and someone would have to create them.

All of these resources, the pebbles, clothes, guns, car tires, trees, buildings, and so forth in a video game are made by people. These people get paid, and so the more detail you want in a game, the more resources you need, and so the more people you have to pay. Taking longer to make the game doesn’t work, as the technology is constantly shifting, so “more people” is pretty much the only going solution at this point. Even licensing IP from other companies is just an abstraction of getting more people to work on the project.

As a result, the drive is now to make games more and more expensive to make, in order to get finer and finer quality of details that add nothing to the narrative, but make the finished package prettier. However, people are not going to pay hundreds of dollars for a game (except possibly that version of MechWarror that came with a big robot control console), so either the game market has to grow without bound, or the industry has to start putting an upper bound on how much they can invest in making a game.

In a way, I’m hoping Pebble is a signpost on the path of excessive detail, a huge amount of clever rendering algorithims and generative textures in pursuit of the perfect simulation of the experience of contemplating a small stone. Whether the signpost says “Welcome!” or “Abandon Hope All Ye Who Enter Here” is an exercise for the reader.


Well THAT’S messy

Posted: October 7th, 2014 | Author: | Filed under: Linux, Scripting | Comments Off

for file in ../connections_2014-10-7-1*; do conn="-c ../connections_"`echo $file | cut -d "_" -f 2`; types="-t ../neuron_types_"`echo $file | cut -d "_" -f 2`; locs="-l ../locations_"`echo $file | cut -d "_" -f 2`; ./pickle_to_json.py $conn $types $locs; done

For all the connection files that were generated today, create three variables called “conn”, “types”, and “locs” that have a command line switch path in them generated from a fixed prefix and a cut from the connection file name. Then invoke the script “pickle_to_json.py” with those variables as arguments.

Effectively, the connection, neuron type, and location files are all related by their date, so this makes a single JSON file out of the multiple files. I just didn’t want to run pickle_to_json.py a bunch of times by hand, as that seemed error-prone.


USB parallel ports under Python on Ubuntu

Posted: May 23rd, 2014 | Author: | Filed under: Arduino, Electronics, Flame Effects, Programming | Comments Off

I have this PCB designed to control four flame effects. Instead of running it on the Arduino, I’m doing an FFT on a laptop and trying to control the solenoid drivers through a USB parallel port adapter on the laptop.

Ubuntu recognizes the USB parallel port adapter, and gives me a port in /dev/usb/lp0. I don’t have permissions to access it, because its user and group are root and lp, and I’m neither of those. The specific error is:

>>> p = parallel.Parallel('/dev/usb/lp0')
Traceback (most recent call last):
  File "", line 1, in
  File "/usr/lib/python2.7/dist-packages/parallel/parallelppdev.py", line 187, in __init__
    self._fd = os.open(self.device, os.O_RDWR)
OSError: [Errno 13] Permission denied: '/dev/usb/lp0'

sudo chmod o+rw /dev/usb/lp0 doesn’t get me any closer, because whatever python-parallel does under the hood is not a legit operation on that dev entry.

>>> p = parallel.Parallel("/dev/usb/lp0")
Traceback (most recent call last):
  File "", line 1, in
  File "/usr/lib/python2.7/dist-packages/parallel/parallelppdev.py", line 189, in __init__
    self.PPEXCL()
  File "/usr/lib/python2.7/dist-packages/parallel/parallelppdev.py", line 241, in PPEXCL
   fcntl.ioctl(self._fd, PPEXCL)
IOError: [Errno 25] Inappropriate ioctl for device

The /dev/usb/lp0 device entry appears to be created by the usblp module. I have a suspicion that what’s going on here is that the device entry created by usblp isn’t claimable the way one created by ppdev would be.

Using rmmod to get rid of usblp doesn’t work, it just gets restarted when I re-insert the USB connector for the adapter. Blacklisting it in /etc/modprobe.d/blacklist.conf just means that the /dev entry doesn’t get created, not that ppdev takes over.

Most reports online also indicate that USB parallel ports don’t really act like parallel ports, but only work for connecting parallel printers. Since I’ve already wasted enough time on this, it’s time to go with plan B. I’m going to fully populate the board, so that it has an Arduino on it, and then interface to that using serial commands and possibly Processing or OpenFrameworks.


Splitting a CSV file into a bunch of columns

Posted: March 26th, 2014 | Author: | Filed under: Research, Scripting | Comments Off

awk -F, '{for(i=1;i<=NF;i++){print $i > "sample"i".csv"}}' yourfile.csv

Does what is says on the tin. Splits your CSV file into a bunch of files, one for each column of the original files. Found here.

I’m using this to pull single channels out of a 60 channel file full of recorded neuron voltages, which I’m then throwing through a little filter test program that I whipped up using this filter library. My main goal is getting rid of 60Hz line noise, but the fluorescent bulbs in the room apparently also make noise at 180Hz and 300Hz.


I waste time to not waste time

Posted: March 3rd, 2014 | Author: | Filed under: B work, Linux | Comments Off

I’m using a web server on my local machine plus an edited /etc/hosts file to serve up a page that reminds me to get back to work when I should be getting back to work, rather than, say, reading facebook. Yes, I can get around this by clearing my hosts file, but that makes it work to get to the blocked sites, and if I’m going to be doing work, it’s not time-wasting is it?

The hosts file looks like this:

ams@robot-lab7:~/weblock$ cat /etc/hosts
127.0.0.1 localhost.localdomain localhost
#I elided a couple of lines here
127.0.0.1 www.facebook.com facebook.com
127.0.0.1 www.dresdencodak.com dresdencodak.com
127.0.0.1 www.xkcd.com xkcd.com
127.0.0.1 www.boingboing.net boingboing.net
127.0.0.1 ab3nd.livejournal.com livejournal.com
127.0.0.1 www.questionablecontent.net questionablecontent.net
127.0.0.1 www.hackday.com hackaday.com

# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts

That takes care of redirecting a lot of pages to localhost, rather than their real IP addresses. On my computer, I have a little web server, which is launched with the command
sudo webfsd -p 80 -f index.htm -u ams -r /home/ams/weblock/

Webfs, and it’s daemon part webfsd, is a static-file-only http server. In this invocation, it runs as my user after binding to port 80 as root, and serves the file index.htm out of the directory /home/ams/weblock. That file is a very simple HTML file:




<br /> You Should Be Working<br />

What should you be doing?




It just shows the text “What should you be doing?” in the middle of the page. This is also interesting because it shows how to center HTML content in the middle of the page, at least for small content. I’m not sure how well this works with larger or more complex content.


I’ve been had!

Posted: February 12th, 2014 | Author: | Filed under: Electronics, Reverse Engineering | Comments Off

I got a “5600mAh” power bank from Aliexpress. It’s an electronic item direct from China at low, low prices, so I assumed it was going to not measure up in some way or other, but until I got it, I didn’t know how.

Overall, the build quality isn’t bad. The case is molded plastic, and snaps together. It’s nice looking and feels solid. The power management PCB in it seems to have good quality solder joints. Not too shabby, and I don’t expect it to catch fire or anything.

The batteries, on the other hand, are where it falls down. The device has two cells in it, 18650 size, 1200mAh each (if their labels are to be believed). They are in parallel, which gets me a total of 2400mAh. That’s slightly more than half of the advertised capacity. Since 5600 isn’t an even multiple of 1200, there’s no way they could get 5600mAh using these batteries, even if they did want a product that could live up to their claims.

For ~$9, I don’t think it’s worth making a fuss over, but now I know what to expect from this device.


“Weaponized” Quadcopters

Posted: February 4th, 2014 | Author: | Filed under: Bad Ideas, Lasers, Robotics, Security | Comments Off

For a long time, I’ve been thinking it would be possible to strap a small explosively-formed penetrator (EFP) to a quadcopter. Then you feed the GPS coordinates of your enemy’s apartment or office into the on-board navigation system, and the quadcopter flies over to their place and fires a hypersonic slug of copper through their window.

Leaving aside the ethical concerns, there are a couple of issues with this. The main one for asymmetric warfare enthusiasts is that it destroys your quadcopter and leaves bits of it at the scene, which wastes resources and gives clues to whoever you were trying to shoot.

Then I saw this little post over at Hackaday. If you put a high wattage diode laser on a quadcopter, you can have it set fire to things. It could probably shoot through a glass window and set fire to things on the inside of the window. Once the place is nicely in flames, you just fly the ‘copter away again, leaving no trace.


Un-ubuntuing Ubuntu…

Posted: February 3rd, 2014 | Author: | Filed under: Linux | Comments Off

..post one of several million, no doubt. Ubuntu is pretty good, but persists in making what I’d regard as irritating desktop usability blunders. One of them is the use of “overlay scrollbars” which are scrollbars that are mostly hidden until you mouse over them. I found this annoying, but whatever, I can deal. It even more or less works, most of the time.

However, it breaks Inkscape. Inkscape’s color picker is a long strip of color patches, which you can click to select stroke and fill colors for drawings. The color picker has a scrollbar. If overlay scrollbars are on, then the entire area of the color picker ends up being the mouse-over area for the overlay scrollbar, so you can’t pick colors.

The fix is to issue the command “gsettings set com.canonical.desktop.interface scrollbar-mode normal” from the command line.


Useful mencoder invocation

Posted: February 3rd, 2014 | Author: | Filed under: Linux, Scripting | Comments Off

mencoder -nosound mf://*.jpg -mf w=1280:h=800:type=jpg:fps=30 -ovc lavc -lavcopts vcodec=mpeg4:vbitrate=2400:mbd=2:keyint=132:v4mv:vqmin=3:lumi_mask=0.07:dark_mask=0.2:mpeg_quant:scplx_mask=0.1:tcplx_mask=0.1:naq -o output_filename.avi

Turns all the JPEG files in the directory you are currently in into a nice quality MPEG-4/AVI file. The width and height in the options after -mf should be changed to match the images. This command line also works for PNG files if you replace both instances of “jpg” with “png”.


Naming things and “ImportError: No module named msg”

Posted: December 10th, 2013 | Author: | Filed under: Programming, Robotics, Scripting | Comments Off

I’m using ROS at school for a project. Part of the project is to detect someone’s hand with a camera, so I’m just looking for a patch of “skin colored*” pixels. ROS organizes software as packages, with nodes in them, and messages that the nodes use to communicate with each other.

For my system, I had a package called “hand_detector” with a source file called “hand_detector.py” and a message type called “hand”. ROS generates the messages, which I then import into my python code with the line:

from hand_detector.msg import *

This gets me the error message: “ImportError: No module named msg”

The reason for this is that python searches the same directory as the executing script for imports before it goes looking anywhere else. Since the file hand_detector.py is the executing script, and is naturally in the directory with itself, python finds it there, imports it into itself, and then tries to find a module called “msg” within hand_detector.py. There’s no .msg in there, so I get the error.

The moral of the story here is don’t name your package and the script in it the same thing. Once I converted the script to just “detector.py”, the problem went away.

*I’m somewhat concerned that I wrote a “white people detector”, as it’s really just thresholding the H part of the HSV color space and counting pixels. Other color spaces may be better for this, but this doesn’t have to be perfect. I just don’t want the robot to be a dick to black people.