Nerd Paradise
Username:   Password:   (Register)

Blog Posts by Blake

Multiple files in Python Hack and Static Variables

Python does almost everything differently from most languages. Many times this is a good thing. But many times this makes large-scale application development delightfully annoying. Particularly, the Object Oriented paradigm in Python is quite useful for small scale apps and scripts with its simplified and loose structure. However, when you want to write an application that's heavily Object-Oriented, the module system for incorporating other files and lack of a proper way of defining a static variable just makes me want to throw my office chair out a 3rd-story window.

From my frequent C# development, I've come to prefer that the structure of your code should never be influenced by the layout of your code files. I should be able to independently structure my code and layout my files in the way that makes best sense.

Another language aside from Python that infamously prevents you from doing this without odd hackery is PHP which I discuss how I get around in this article. Consider this article the Python equivalent of that.

For those of you not familiar with C#, file separation does not matter in C#. You could, in theory, concatenate all the code together into one file and it would all compile the same. Or conversely, you could even split up classes into multiple files and it will still compile the same. This gives you much freedom to lay out your file structure any way you please.

On that note, when writing a Python script, you could also put everything in one file and Python would be happy. So for larger projects, I create a concatenation script and a batch file. The concatenation script will recursively go through all my python files in the directory and add them all together and create a super python file. The batch file, called "run.bat", will kick off the concatenation script and run the resulting file. I'm probably going to receive a lot of ridicule of this method, so I'll go ahead and point out the obvious benefits and defects of this method:

Pros:

  • You can lay out your file structure any way you wish. You are no longer at the mercy of using Python's module system.
  • Py2exe is often fickle when dealing with multiple files. This makes that process a bit easier.
  • Static variables are much more trivial to do now. Now you just define a variable outside of the class that needs it. This variable is now in the root scope of your application and all other classes can see the same instance of it. The only trick is making sure your variable doesn't refer to anything that hasn't been included in the concatenated super-file yet. I'll show you how to get around this in the example concatenation script below.
  • Pyc files are no longer created.

Cons:

  • You will make any IDE really angry. If you're just using a basic text editor like Notepad++ or Crimson, then this really doesn't matter.
  • Any call stack will have incorrect line numbers. You have to debug your application by looking at the concatenated python super-file to get correct line numbers. But hey, you shouldn't be writing code that crashes anyway. ;)


Sample project:


project_folder\util\concat.py


In this file, I recursively fetch the contents of all files in the "source" directory. There are two files I call out particularly. "imports.py" and "main.py" which are all the import statements needed for the whole project, and the root point of execution, respectively. The imports.py file is included in the final output first and the main.py file is included last after all class definitions have been added. If I wish, I can add a line that says "--STATIC--" to any of the files. Anything after this line will be considered a "static variable" and will be appended to the final output after all class definitions, and before the contents of main.py are included. This prevents any weird ordered dependency issues.

import os

def read_file(file):
  c = open(file, 'rt')
  t = c.read()
  c.close()
  return t

def write_file(file, text):
  c = open(file, 'wt')
  c.write(text)
  c.close()

def concat_result(folder):
  text = ''
  statics = ''
  for file in os.listdir(folder):
    filepath = folder + os.sep + file
    if not filepath in exclude:
      if os.path.isdir(filepath):
        output = concat_result(filepath)
        text += output[0]
        statics += output[1]
      else:
        content = read_file(filepath)
        pieces = content.split('--STATIC--')
        static = ''
        code = pieces[0]
        if len(pieces) == 2:
          static = pieces[1]
        
        text += '\n'.join([
          '',
          '',
          '#' + '-' * 20,
          '# ' + filepath,
          '#' + '-' * 20,
          code,
          ''])
        statics += "\n" + static
  return (text, statics)

root = 'source' + os.sep + 'main.py'
imports = 'source' + os.sep + 'imports.py'
exclude = [root, imports]

output = read_file(imports) + "\n\n"
code = concat_result('source')
output += code[0] + "\n"
output += "\n\n#--STATIC VALUES--\n\n"
output += code[1] + "\n\n"
output += "\n\n" + read_file(root) + "\n"
write_file('run.py', output)


project_folder\run.bat

This file is pretty simple. Run the concatenation script, and run the output.
@echo OFF
python util\concat.py
python run.py


project_folder\source\main.py

# this is the root point of execution. 
# No imports are required here. 
# Anything that ought to be initialized before the script runs has already been initialized

print ("hi")


project_folder\source\imports.py


# this will be included at the very top of the big python script. 
import os
import math



project_folder\source\Foo.py


# I want this to be a singleton
class Foo:

  def __init__(self):
    global FooInstanceCounter
    if FooInstanceCounter > 0:
      raise Exception('Multiple instances of Foo. Foo should be a singleton')
    FooInstanceCounter += 1

--STATIC--
FooInstanceCounter = 0
FooInstance = Foo()
Share on Facebook Tweet Submit to Stumble Upon Reddit
Tags: OOP, Python
1 Comment

How to Make Your Own Media Player Replacement: Part 1

Tired of Windows Media Player? WinAmp getting too clunky these days? Has the inconvenience of the VLC UI failed your easy listening scenarios? It's time to make your own media player.

If you don't have Visual Studio already, download the express edition for C#. If you're using a version of Windows prior to Windows 7, you'll want to also download the .NET Framework 3.5 SP1 if you don't already have it. I think Visual Studio Express will prompt you to download it, but I can't test that theory because I already have it installed on this machine.

Okay. Got everything installed? Good. Launch Visual Studio and create a new project. (File --> New Project...)
superduper01
Choose WPF Application. I'm calling it SuperDuperPlayer. You can call it whatever you want. No funny punctuation or spaces, please.

Alright. Now you have this...
superduper02
Chances are you are presented with a UI designer. We won't be using that because we are big kids. Click the tab at the bottom that says "XAML" so you see scary XML code instead. This is where 30% of the magic will take place. Paste the following code in.

<Window x:Class="SuperDuperPlayer.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:SuperDuperPlayer"
    Title="Super Duper Player" Height="300" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="40"/>
            <RowDefinition Height="40"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        
        <!-- teehee, I'm invisibule! -->
        <MediaElement x:Name="player" Width="0" Height="0" LoadedBehavior="Manual" />
        
        <Grid Grid.Row="0">
            <TextBlock HorizontalAlignment="Left" x:Name="Time" Text="00:00 / 00:00" />
            <TextBlock HorizontalAlignment="Left" x:Name="Title" Margin="100,0,0,0" Text="Current Song" />
        </Grid>
        
        <Grid Grid.Row="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>

            <Button x:Name="button_back" Grid.Column="0">Back</Button>
            <Button x:Name="button_stop" Grid.Column="1">Stop</Button>
            <Button x:Name="button_play" Grid.Column="2">Play/Pause</Button>
            <Button x:Name="button_forward" Grid.Column="3">Forward</Button>
            <Button x:Name="button_add" Grid.Column="4">Add File</Button>
            <Button x:Name="button_repeat" Grid.Column="5">Repeat [On]</Button>
            <Button x:Name="button_shuffle" Grid.Column="6">Shuffle [Off]</Button>
        </Grid>
        
        <ScrollViewer Grid.Row="2">
            <ListBox>
                <!-- magic playlist -->
            </ListBox>
        </ScrollViewer>
    </Grid>
</Window>


This is just UI code. No brains to it yet. The magical piece is the tag called MediaElement. This little piece of UI encapsulates all possible means of playback you will need to make a sufficient media player. It's built in to the .NET Framework. It has methods such as Play, Pause, Stop, etc that will magically work for any supported media file. This is why you can make your own media player without knowing an ounce about codecs or compression formats. You may be curious if Media Player runs off the same control and if so won't our media player be just as slow? I don't know if Media Player uses the same native control, however, it is most definitely not slow. It's minimalistic and so if you have no other frills in your media player, it should load lightning fast. Media Player is slow because it loads millions of other features that you probably don't need if you just want to load a simple playlist of mp3's and listen.

If you hit F5, it will actually launch Super Duper Player and you'll see something like this...

superduper04

Alright. C# programs can't exist without C# code, so let's get cracking. This is where the other 70% of the magic comes in. Right click on SuperDuperPlayer.csproj (the little green icon that says "C#" in it) and then click Add --> Class...

Let's name this class Song...
superduper03

Do the same thing again and call the next class Playlist. Now you should have two additional files in your solution explorer called Song.cs and Playlist.cs. Double click on them.

Let's look at Song.cs

This class will represent the actual song entity, both logically, and the thingy that will appear in the playlist. All we need to include in this class is everything we need to know about a snog. Basically just the title and the filename. Here's the spectacularly unspectacular code I wrote up...

using System;

namespace SuperDuperPlayer
{
    public class Song
    {
        public Song(string title, string path)
        {
            this.Path = path;
            this.Title = title;
        }

        public string Title { getprivate set; }
        public string Path { getprivate set; }

        public override string ToString()
        {
            return this.Title;
        }
    }
}


I went ahead and overrode the .ToString method so that when it appears in the playlist without a DataTemplate, it'll actually be somewhat useful. Smile and nod.

Now the playlist is a bit more complicated and I now somewhat regret the name I chose for it. "SongManager" might be a better name for it. But too late! This will serve as the brain of our app, mostly. it'll send messages to our MediaElement to stop and start playing which songs based on the buttons you press and the settings you have set (shuffle/repeat). There's significantly more code, but it's still pretty simple stuff...

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows.Controls;

namespace SuperDuperPlayer
{
    public class Playlist
    {
        private bool shuffle = false;
        private bool repeat = false;
        private bool paused = false;
        private bool isPlaying = false;

        private ObservableCollection<Song> songs;
        private MediaElement player;

        public Playlist(MediaElement mediaElement)
        {
            this.songs = new ObservableCollection<Song>();
            this.player = mediaElement;
        }

        public int ActiveIndex { getset; }

        public ObservableCollection<Song> Songs
        {
            get { return this.songs; }
        }

        public void AddSong(string path)
        {
            if (System.IO.File.Exists(path))
            {
                this.songs.Add(new Song(
                    System.IO.Path.GetFileNameWithoutExtension(path),
                    path));
            }
        }

        public void DeleteSong()
        {
            if (this.songs.Count > this.ActiveIndex)
            {
                this.songs.RemoveAt(this.ActiveIndex);
            }
        }

        public void Play()
        {
            if (!this.paused && this.isPlaying)
            {
                this.Pause();
            }
            else
            {
                if (!this.paused && this.Songs.Count > this.ActiveIndex)
                {
                    Song songToPlay = this.Songs[this.ActiveIndex];
                    this.player.Source = new Uri(songToPlay.Path);
                }
                this.player.Play();
                this.paused = false;
                this.isPlaying = true;
            }
        }

        public void Stop()
        {
            this.player.Stop();
            this.player.Position = new TimeSpan(0);
            this.isPlaying = false;
            this.paused = false;
        }

        public void Pause()
        {
            this.paused = true;
            this.isPlaying = false;
            this.player.Pause();
        }

        public void Next()
        {
            this.Stop();
            this.ActiveIndex++;
            if (this.ActiveIndex >= this.songs.Count)
            {
                this.ActiveIndex = 0;
            }

            if (this.isPlaying)
            {
                this.Play();
            }
        }

        public void Prev()
        {
            this.Stop();
            this.ActiveIndex--;
            if (this.ActiveIndex < 0)
            {
                this.ActiveIndex = this.songs.Count - 1;
            }
            if (this.isPlaying)
            {
                this.Play();
            }
        }

        public void ToggleRepeat()
        {
            this.repeat = !this.repeat;
        }

        public void ToggleShuffle()
        {
            this.shuffle = !this.shuffle;
        }
    }
}


The only data this class maintains is a list of songs, a few boolean flags for some useful stuff, and an integer to indicate which file in the list is currently playing. The methods basically map to actions a user can perform by hitting buttons we have provided. This methods will set the song MediaElement is currently playing (via its Source property) and start or stop it. The most complicated aspect so far is the code to ensure that the ActiveIndex does not go out of bounds of the number of item in the song list. I use an ObservableCollection instead of just a List because I'm going to bind this collection to the ListBox you may have seen at the bottom of the first bit of Xaml code.

One last thing. We need to tie this playlist object to the actual UI. Next to Window1.xaml, you'll notice a little + icon indicating more things below this file. Expand it. You'll see a Window1.xaml.cs.

Open it up and make it look like this...

using System;
using System.Windows;

namespace SuperDuperPlayer
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        private Playlist brain;

        public Window1()
        {
            InitializeComponent();
            this.DataContext = this;
            this.brain = new Playlist(this.player);

            this.button_add.Click += new RoutedEventHandler(button_add_Click);
            this.button_back.Click += new RoutedEventHandler(button_back_Click);
            this.button_forward.Click += new RoutedEventHandler(button_forward_Click);
            this.button_play.Click += new RoutedEventHandler(button_play_Click);
            this.button_repeat.Click += new RoutedEventHandler(button_repeat_Click);
            this.button_shuffle.Click += new RoutedEventHandler(button_shuffle_Click);
            this.button_stop.Click += new RoutedEventHandler(button_stop_Click);
        }

        void button_stop_Click(object sender, RoutedEventArgs e)
        {
            this.brain.Stop();
        }

        void button_shuffle_Click(object sender, RoutedEventArgs e)
        {
            this.brain.ToggleShuffle();
        }

        void button_repeat_Click(object sender, RoutedEventArgs e)
        {
            this.brain.ToggleRepeat();
        }

        void button_play_Click(object sender, RoutedEventArgs e)
        {
            this.brain.Play();
        }

        void button_forward_Click(object sender, RoutedEventArgs e)
        {
            this.brain.Next();
        }

        void button_back_Click(object sender, RoutedEventArgs e)
        {
            this.brain.Prev();
        }

        void button_add_Click(object sender, RoutedEventArgs e)
        {
            // yeah, I know. We'll hook up the open file dialog later.
            this.brain.AddSong(@"C:\users\Blake\desktop\PurplePeopleEater.mp3");
        }

        public ObservableCollection<Song> Songs
        {
            get { return this.brain.Songs; }
        }
    }
}


There shouldn't be any logic in this code. This class should only take user input and convert them into commands that are directly called into the Playlist class we have. I'm going to create a file-open dialog later to browse for mp3's, so for the time being, I've hardcoded a path to a file on my harddrive.

So now we have almost everything hooked up in the most basic way. One last thing...

I've exposed the ObservableCollection of Songs from Window1.xaml.cs so that we can bind the ListBox's ItemSource to it so we can actually see a list of songs. So go back to Window1.xaml and fix up the ListBox in the ScrollViewer to look like this...

        <ScrollViewer Grid.Row="2">
            <ListBox ItemsSource="{Binding Path=Songs}">
                <!-- magic playlist -->
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Title}"/>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </ScrollViewer>


Go ahead and hit F5 and run it. Press the Add File button and then hit play. The song you hardcoded should appear in the playlist and start playing.

superduper06

But listening to the same file over and over again is no fun. So let's add a file browse dialog.

Go back to Window1.xaml.cs to your button_add_Click method...
void button_add_Click(object sender, RoutedEventArgs e)
{
        // yeah, I know. We'll hook up the open file dialog later.
        this.brain.AddSong(@"C:\users\Blake\desktop\PurplePeopleEater.mp3");
}


The file open dialog exists in WinForms. Unfortunately, we're in a WPF project, so we'll have to manually add a reference to the WinForms assembly. But no biggie. Right click on the References item located 2 entries below SuperDuperPlayer.csproj in the Solution Explorer and click "Add Reference...".

superduper07

Find System.Windows.Forms in the .NET tab and add it. This allows us to use any of the legacy classes in the System.Windows.Forms namespace. Such as the OpenFileDialog class.

So now change that method to this:

        void button_add_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.OpenFileDialog dialog = new System.Windows.Forms.OpenFileDialog();
            dialog.Filter = "MP3's (*.mp3)|*.mp3|All files (*.*)|*.*";
            dialog.Multiselect = true;
            System.Windows.Forms.DialogResult result = dialog.ShowDialog();
            if (result == System.Windows.Forms.DialogResult.OK)
            {
                foreach (string filename in dialog.FileNames)
                {
                    if (System.IO.File.Exists(filename))
                    {
                        this.brain.AddSong(filename);
                    }
                }
            }
        }


And that's about it. See? Nothing magical at all. Next post, I'll show you how to make a slidey bar that updates in real time and make the time show the correct amount and song title. Then we'll create a playlist file format so that we can save playlists and open them later.
Share on Facebook Tweet Submit to Stumble Upon Reddit
Tags: .NET, C#, media
0 Comments

MSPaint Tutorial: Adding a Lake to a Photo

So I was browsing for local homes and I found a cabin that was going for 1.5 million dollars...

mspaint_lake01
Geeze. For that kind of money, there has to be a lake or something. Let's add a lake.

mspaint_lake02
First, crop off some of the lawn. Make sure that all the tree shadows are gone. To crop, just drag the little node at the bottom of the picture up.

Once you have that cropped, copy the remaining portion of the picture (Select All, then Copy).

Then expand the picture your picture so you have room to paste in the lake.

mspaint_lake03
This may seem arbitrary. Open a new window of mspaint. Shrink it down to a few pixels. Then paste in the picture you have on the clipboard. This will stretch the image to the size of the image if you have a later version of mspaint, or it will prompt you to expand the image if you have an older version of mspaint. Click yes, if that is the case. Now delete the image. You should now have a blank image the size of the cabin picture. Now double the size by stretching it 200% horizontally and Vertially (Ctrl + W).

mspaint_lake04
Now, draw a horizontal red line. Now select the whole picture and, while holding down Ctrl, click and drag the image up by 2 pixels. On the left side, there are two modes to choose from, opaque and transparent. Select transparent. Now you should have two horizontal lines. Repeat this process so that you have 4 horizontal lines. Then 8. Then 16. Do so until you've vertically filled the image with horizontal red lines. Now stretch them horizontally so that it fills the whole image. Keep this window open for later use.

mspaint_lake05
Remember that picture you had on the clipboard? Now open TWO more mspaint windows and paste it in each of those. Stretch both of them to 200% of their oritinal size (Ctrl + W). They should both look like this...
mspaint_lake06

Now go back to your horizontal red lines and copy it and paste it onto one of your 200% size cabin pictures. Make sure you're in transparent mode so you should have something like this...
mspaint_lake07

Now select the whole image (Ctrl+A) and copy and paste this into the other 200% size cabin picture. Set the background color to red and make sure you're in transparent mode. If you did it right, it should look the way it did originally.

Then drag the selected portion down by about 7-10 pixels. You should now have something like this...
mspaint_lake08

Now in your stretch and skew menu (Ctrl + W), shrink this down to 50% of its original size so that you have this...
mspaint_lake09

Now take this new image and copy and paste it into another mspaint window. Scale them both up to 200% of their original size again so that you have two large versions of this picture. Repeat the same process of pasting the vertical lines. This time, instead of dragging one copy 7-10 pixels, drag it about 3-5 pixels, so that you have this...
mspaint_lake10

Shrink this by 50% (Ctrl + W) so that it's its original size again...
mspaint_lake11

In the flip and rotate menu (Ctrl + R), flip the image vertically and paste it into your original image where you now have all that whitespace.
mspaint_lake12

Lake!

Yeah, I know there's no shoreline. If you're that picky, go use Photoshop.
Share on Facebook Tweet Submit to Stumble Upon Reddit
Tags: MSPaint
1 Comment

The Twenty-0's: The Internet Becomes Cool

It's a nice relief to finally have a decade after the 1940's that we can look back at and say "You know? The hairstyles actually weren't all that bad." But I'm sure that's not how we will directly remember it.

At the end of 1999, the Wachowski brothers showed us Keanu Reeves with basically an ethernet port on the back of his neck. Perhaps this was a warning for the next decade to come. At the time, giant boxy cellphones were for important businessmen and kids of rich parents. In fact, the nerdity test on the original NP which went up in 1999 had an interesting question on it:

Do you own a cell phone?

(those from outside the US will have to excuse me on this, since the cellphone revolution was about 4 years ahead in all other developed countries)

Google didn't exist, 56k modems were pretty fancy, people would call a business and ask for directions if they didn't know how to drive to it, Times New Roman was hip, page hit counters were a viable .com startup business model, and people used Internet Explorer.

How things have changed.

Now we have magical screens we keep in our pockets that can tell us what our old high school friends and distant relatives are doing every second of every day. I suppose we'll remember this decade as the rise of being wired-in. The center of this revolution, aside from the predictably shrinking hardware size and growing speed, are the social networks.

Jocks, Nerds, and the Social Network Bridge


When something new and scary comes out, the fearless nerds are the ones that adopt it. Usually they're the only ones that know about it. Anyone that spent more than 10 minutes on the internet surely must be suffering from a social disorder. The nerds ruled the internet and words were spelled correctly. Once something becomes accessible, a business model out there will make it hip. The social networks converted the internet from something that was a tool and an intellectual playground into the social norm. The rest of the world has come to the internet and they are here to stay. But now that the bulk of society is using social networking, social networking must now obey the laws of trends and styles that plague the social landscape. That means just as styles come and go, so will social networks.

Social networks, past and present


Friendster was "cool" in 2002. Now it is dead. Friendster was created to serve as a simple internet spot where you and your friends could socialize. This was novel, but ultimately people realized that talking in person or over the phone was more efficient. There was no value-add and the initial novelty wore off.

MySpace comes along in 2003 and adds a rich feature set to the equation. MySpaces focuses on YOU. You can express yourself and keep a blog. People learn things about you they probably wouldn't in person unless it was a really awkward conversation. This quickly wiped Friendster off the map which seemed outdated by comparison.

Facebook came along in 2004 and disregarded the featureset which, to most nerds at the time were an annoying aspect of myspace anyway. The focus was finding out information about other people you already knew. Actual "networking". Because it was closed to colleges only and you could only browse people within your college, it had a much smaller community-like feeling. Later they opened it to everyone and that has gone away. It also requires your real name which makes it ideal to find long lost childhood friends. Meanwhile, MySpace continued to decline and will fall forgotten next to Friendster within a few years.

Social networks, the future


So what else can be done? It seems like facebook has hit the peak of social networking and there isn't really any other way to "network" further. Sure, there's Twitter which basically raises the fidelity at which we find out what our friends on the opposite coast are doing. But each of the previous social network kings thrived off a new paradigm:

  • Friendster: opening move, creating a place where you can talk to friends online
  • MySpace: focuses on you, brag about yourself and create an online nest where you post pictures of yourself drunk
  • Facebook: network with others, find friends of friends and connect with old friends

The only thing that seems to be lacking is meeting new people. In the 90's and early 20-oh's (is that what we're going to call them?), there was a strong negative association with meeting people on the internet thanks to skeptical parents who watch Chris Hansen. In fact, the latter half of the 20th century had a much stronger negative view of strangers than before in general.

As I mentioned earlier, the nerds tend to pave the way of new trends and technology, and the only social aspect of the internet that the normal crowd has not been drawn to is mingling with new people. The nerd crowd still rules IRC and many forums, but the meeting-new-people aspect has not been baked into the paradigms of any major social network yet.

Eventually facebook will fall. They called me crazy in 2006 when I said MySpace would fall. And now it mostly has. No clear contender has presented itself, but I imagine its paradigm will fulfill this social networking gap that currently exists, and as a rippling effect will make society a much more friendly and less disconnected and mistrusting place, which I think is how the next decade may be remembered.

Unless of course there's a nuclear war.
Share on Facebook Tweet Submit to Stumble Upon Reddit
1 Comment

How to make a Video Game in Python: Part 1

Video Game Development...AT HOME!


Remember Omniventure? Of course you do. That was so much damn fun. Since I wrote Omniventure in under a day, it was a bad design and I was into crunch time when I started it. The code for it is not something I'd like to use as an educational example. But the concept is something that I would love to share.

SO...

This series of posts will be an extended tutorial on how to make a (possibly not so) simple 2D video game.

The premise will be reminiscent of Omniventure. It will be a side-scrolling video game and you can choose any of the admins as your character in the style of Super Mario Bros. 2 (they don't know about this yet. Surprise!).

The storyline:

All the evil 10-year-old script kiddies of the world have combined powers and have hacked into the NP database. They have stolen all the steps to the Rubik's Cube solution and won't give them back. It's up to our fearless admins to recover them!

I will make this game WITH MY BARE HANDS. And I will show you how to do it too.

For this game, we will be using Python alongside with PyGame. PyGame is a set of python libraries that wrap low level hardware guts in a handy dandy interface that allows you to interact with the screen and mouse and keyboard and soundcard in a manner that is actually NOT painful and from within Python. Double win!

Pygame = fast, easy, cross-platform && fun!

This tutorial series will assume you already know Python and Object Oriented Programming amongs other common programming techniques. You may not necessarily have to know OO in association with Python, but that can be picked up in a jiffy if you already have a strong handle on both.

I will also try to make these tutorials interesting from a high-level perspective. Even if you aren't into programming, I still hope to captivate your interest. Kind of like those nature shows. I'm not a biologist and I don't care about the Antarctic striped beaver-lope. But I watch the show anyway.

But for those of you who do decide to follow along closely in the technical side of things, more than anything, this is a tutorial on design rather than just video game programming. I will make mistakes. Some of them will be on purpose (or so you will be lead to believe) just to show how much a bad design can come back to bite you and how to handle or fix them.

Part 1: Setting up your computer


I'm going to be honest with you. Setting up your computer for this is going to be a pain in the ass. But you only have to do it once.

www.python.org - The latest version of Python as of this article's post date is 2.5. Download that for your operating system. Install it. The installer should be fairly straight forward if you are on windows. If you're not on windows, you already know what the hell you're doing anyway so I don't really need to spell anything out here.

www.pygame.org - Python alone can't do neat video game style stuff. Like I said earlier, PyGame wraps low-level hardware functionality on a high Python level. The best of both worlds! PyGame is a set of libraries that gets installed WITHIN Python. It is not a program itself. So you shouldn't expect any new snazzy shortcuts on your desktop when you install it. The hardest thing about installing PyGame is finding the right file to download and install. The download page is gawd awful. It's just a default file listing generated by the server. Chances are the file you want is the one with the one of the more recent dates next to it. If you're on windows, it's easy. Just figure out which file has the .exe extension. Other OS'es may involve compiling PyGame from source code. But again, if you wanted the easy way out of things, you'd be on Windows.

www.eclipse.org - I made this entire site in notepad. It is comprised of hundreds of wee little PHP scripts working together like an army of drunken monkey servants bringing you the quality page you see here. Do NOT attempt to make a large-scale programming project like this game in notepad. That's crazy talk. You NEED an IDE. If you know what you're doing and have a favorite IDE that supports python, use that. Personally, I enjoy eclipse for large-scale Python development. If you want to use eclipse, download the latest version of their SDK. It'll give you a huge-ass zip file. Unzip it. No installation! The great thing about eclipse is that it's ready to use out of the box in any folder. It doesn't have any tentacles that dig into your operating system. When you don't want eclipse anymore, you just delete the files. No other nasty uninstallation or cleanup. More programs need to be written this way. Navigate into the unzipped eclipse folder and find the executable. Double click on it.

Did it give you an error yapping about Java? Eclipse is written in Java. If you don't have a JVM installed, you'll need to do that now...

java.sun.com - download the latest Java Development Kit (JDK). From this page, go to the downloads tab and go to Java SE. You should see a link for downloading JDK 6. Download the basic one. Follow the directions from there on out.

Ok, now that you've got eclipse in a working state, run it. It'll prompt you for a workspace. Press OK. Close the esoteric welcome screen (there's a tab at the top).

Now it's time to set up Eclipse for Python development...

pydev.sourceforge.net - Eclipse supports Java by default. You need to download an eclipse plugin for Python support. We'll be using PyDev. In the help menu, select "Software Updates" and "Find and Install" (yeah, intuitive, I know). Click the "Search for new features to install" option. Click next. Add a new remote site. Call it PyDev and give the URL that is given on pydev's website which should be "http://pydev.sourceforge.net/updates/". Press Okidokey and Click next. Check the PyDev box. Click Next. MAKE SURE YOU READ THE LICENSE AGREEMENT IN FULL. THERE IS ACTUALLY IMPORTANT STUFF IN THIS ONE. Press 'accept'. Click Next. Click Finish. Wait. Click Install All. Click Yes. Wait. Press OK for the workspace again. Go to Window → Preferences. Under the PyDev node, go to "Interpreter - Python". Click the "New..." button. Navigate to where you installed Python and select python.exe. Press OK. Press OK. Wait. Go to File → New → Project. Select PyDev → PyDev Project. Click Next. Type CubeQuest for the project name. Click the Python version that most resembles the version you installed. Click Finish.

OK. You are FINALLY ready to start making a game.

The next tutorial will show you a basic game loop that takes in input and turns it into rudimentary output.
Share on Facebook Tweet Submit to Stumble Upon Reddit
1 Comment
List all posts by Blake
Most recent posts by Blake
 
Users online:
Your IP: 38.107.191.82
Current Time: 9 Cado 14:3 - 9.52.19 ?
Blake O'Hare | asdfjkl; | Two Cans & String | Game Requests