Perl 6 on steroids: Through The Window
Posted: 23/03/2014 Filed under: Perl | Tags: games, perl, perl6, steroids 5 Comments
I got into programming because I wanted to write games. I played games as a kid (wolfenstein 3d, putt-putt, I don’t remember the rest of the names), and I thought “when I grow up, I’m going to write games!”
I never really did; at some point I realized I’ve written more compilers than games: whatever happened to the childhood dream? So I thought I’ll write some, to try and learn something new.
With two friends from work I went to javascript game programming conference – it was the only game conf I’ve ever heard of, so I thought “javascript or not, let’s see how gamedev geeks party”. The universal “let’s create idiotic games and make a lot of money on ads and In-App-Purchases” attitude of the startup crowd discouraged me a little bit, but I tried to ignore that bit and focus on the technical content. I never liked javascript, I didn’t really want to use it for any kind of programming, and frankly, working in Perl and Python I grew tired of dynamic typing altogether, but I thought “hmm, maybe if I created a superset of JS that has nice type annotations, that the compiler checks and then drops, emitting vanilla JS, that wouldn’t be so bad to write code in”. I consulted a friend of mine, and, as it usually happens, it turned out that such thing already exists: it’s called Typescript, and Microsoft created it long ago. Oh well, let’s give it a try.
Why am I writing about all this? Where does Perl 6 come in? Thing is, when I started programming in Typescript, I got annoyed. It’s severly underdocumented, undersupported, development is not pleasant, because you get some errors from the compiler and then different errors from a browser, but the worst thing is: it was slow! It was so slow it was unbearable, and I thought “ah, screw it. I’ll be better off with Perl 6”.
I chose Perl 6 for performance reasons! Ain’t that something to tell my grandkids about.
Of course, creating games in Perl 6 is not so trivial: I’ll have to write the engine/framework/whatever myself. Time to roll the sleeves up and get to work.
I got quite motivated by http://lessmilk.com. This guy creates a new game every week to learn game development. Cool thing! He was describing phaser.js in one of his articles, so I created Steroids, and modelled it after Phaser.
Why steroids? Well, at some point I ported my C Asteroids to Perl 6, as a proof of concept, to see if it can indeed handle 60fps games (it can), and the “steroids” bit somewhat got stuck in my mind. Also, being on steroids gives you much more flexibility than, say, being on the rails. Don’t worry, nothing bad about being on Steroids: Just ask Duke Nukem, he got by just fine.
So, Perl 6 on Steroids was born. I started writing a running-jumping game, and abstracting the commonly used bits to a module as I went on. Why a running-jumping game? Well, you asked for it: it’s time for another backstory:
Ever wrote in a backseat of the car as a kid, looking out the window? Did you imagine a person running along the car, jumping over obstacles? I did, and from what I’ve heard I am not the only one. Thus, “Through the Window” was born: a game where a man runs along the horizon, jumping over trees and cows, being the first showcase for Steroids, and a reason for it to exist.
The post is getting lenghty enough, and there’s much to announce still, so I’ll run through the 80 lines of code really quickly to show you what Steroids gives you. You can read the entire source code here
class Game is Steroids::Game
You create a class that inherits from Steroids::Game. You need to define at least two methods for it to make any sense: create() and update(). The former initializes the game, and the latter is called 60 times per second to update the game state.
Some of the things you may want to do in the create() method:
self.load_bitmap(‘background’, ‘assets/background.bmp’);
self.add_sprite(‘background’, 0, 0);
Pretty self-explanatory. Steroids handles loading bitmaps from disk for you, and putting them in a scene.
self.load_bitmap(‘runner’, ‘assets/runner.bmp’);
$!runner = self.add_sprite(‘runner’, 50, GROUNDLEVEL);
$!runner.y -= $!runner.h;
$!runner.gravity = 1;$!runner.when({ $_.y > GROUNDLEVEL – $_.h }, {$!runner.y = GROUNDLEVEL – $!runner.h;$!runner.velocity[1] = 0;});
method update {if @!obstaclesand @!obstacles[0].x < ($!runner.x + $!runner.w) < (@!obstacles[0].x + @!obstacles[0].w)and $!runner.y + $!runner.h > @!obstacles[0].y {say “===========================================”;say ” Game over! You traveled $!distance pixels “;say “===========================================”;say “”;self.quit;}
if $!distance > $!last-obstacle + 40 and rand > 0.9 {my $s = self.add_sprite(<cow tree>.pick, self.width, GROUNDLEVEL);$s.y -= $s.h;$s.velocity[0] = -12;@!obstacles.push: $s;$s.when({ $_.x < 0 – $_.w }, {self.remove_sprite($_);@!obstacles.shift;});$!last-obstacle = $!distance;}
if self.is_pressed(“Space”) and $!runner.y == GROUNDLEVEL – $!runner.h {$!runner.velocity[1] = -22;}