Monday, December 30, 2013

Adding Getters and Setters to a Ball of Yarn

That doesn't sound very useful. But you know what does? Adding getters and setters to a coffee-script class - after all, typescript has them, and I want to have similar functionality in my coffee-script.

Getters and setters are implemented using the Object.defineProperty method. We could implement each property with a call to this method, but I don't want to type a bunch of cruft to define each class property. So lets do it meta - after all, coffee-script IS javascript!


Function::get = ($def) ->
  $name = Object.keys($def)[0]
  Object.defineProperty @::, $name, {get: $def[$name], configurable: yes}
Notice that I've augmented the Function object (:: is coffescript notation for prototype).  This will add a get method to all functions, and in coffeescript a class is a function. We can define set the same way:

Function::set = ($def) ->
  $name = Object.keys($def)[0]
  Object.defineProperty @::, $name, {set: $def[$name], configurable: yes}
But what does that get us? Lets look at an implementation:

class HeartOfGold

  _answer: 0

  @get answer: -> @_answer
  @set answer: (value) -> @_answer = value

Inside of a class definition, but outside of a method scope, @ (this) refers to the class. So we are calling the get method of the class that we defined earlier, to define a getter on the class.

And, if we explicitly invoke the super object, we can inherit the new attributes:
class Zaphod extends HeartOfGold
 
  # Explicit access to super is used to access property behavior
  @get answer: -> Zaphod.__super__.answer * 2 * Math.PI
  @set answer: (value) -> Zaphod.__super__.answer = value
 
  constructor: (value) ->
    @answer = value
 
 
meaning_of_life = new Zaphod(6.684507609859605)
console.log "Zaphod says that the meaning of life, the universe, and everything is "+meaning_of_life.answer
 
Run like this -
$ coffee heartofgold
Zaphod says that the meaning of life, the universe, and everything is 42
Now aren't we glad we didn't turn into a big ball of yarn!

(updated: to use google prettify rather than embedded gists. It makes it easier to focus on the code)

Friday, December 27, 2013

Set Your Coffee-Scripts to Stun

After reviewing several HTML5 game engines, I've decided to spend some time with Phaser. My primary consideration has to be gameplay, and after trying a bunch of demos, I felt that Phaser was one of the top contenders. With comparable gameplay, I next looked at the development environment and framework.

Here is why I like Phaser:
  • No special workbench is needed. My favorite editor will work, as well as the one I happen to be using.
  • Cross platform on the dev side. I use Linux.
  • Ecma standard script - not ActionScript or anything else, but real javascript.
  • Agnostic oop - I'm not forced into any class patterns.
Best of all, due to those last two points, Phaser is compatible with coffee-script. As my tag cloud tells me, that is my favorite topic,  so with a bit of playing around, I ported this tutorial to coffee-script.

At the moment, there is a workaround patch needed for coffee-script classes to work. This could be fixed in an upcoming release, but for now we need to ensure that the prototype.constructor is set:

Phaser.Game::constructor = Phaser.Game    # patch prototype
Phaser.State::constructor = Phaser.State  # patch prototype

Update: I just downloaded Phaser 2.0.2, and found that the prototype patch described above was no longer needed.

Now the code - this is just the final listing from the demo:


class Game extends Phaser.Game

  constructor: ->

    super 800, 600, Phaser.AUTO
    @state.add 'Stage', Stage, false
    @state.start 'Stage'

class Stage extends Phaser.State

  player: null
  platforms: null
  cursors: null
  
  stars: null
  score: 0
  scoreText: null

  preload: ->

    @load.image 'sky', 'assets/sky.png'
    @load.image 'ground', 'assets/platform.png'
    @load.image 'star', 'assets/star.png'
    @load.spritesheet 'dude', 'assets/dude.png', 32, 48


  create: ->
    
    #  A simple background for our game
    @add.sprite  0, 0, 'sky'

    #  The platforms group contains the ground and the 2 ledges we can jump on
    @platforms = @add.group()

    # Here we create the ground.
    ground = @platforms.create(0, @world.height - 64, 'ground')

    #  Scale it to fit the width of the game (the original sprite is 400x32 in size)
    ground.scale.setTo 2, 2

    #  This stops it from falling away when you jump on it
    ground.body.immovable = true

    #  Now let's create two ledges
    ledge = @platforms.create(400, 400, 'ground')
    ledge.body.immovable = true

    ledge = @platforms.create(-150, 250, 'ground')
    ledge.body.immovable = true

    # The player and its settings
    @player = @add.sprite(32, @world.height - 150, 'dude')

    #  Player physics properties. Give the little guy a slight bounce.
    @player.body.bounce.y = 0.2
    @player.body.gravity.y = 6
    @player.body.collideWorldBounds = true

    #  Our two animations, walking left and right.
    @player.animations.add 'left', [0, 1, 2, 3], 10, true
    @player.animations.add 'right', [5, 6, 7, 8], 10, true

    #  Finally some stars to collect
    @stars = @add.group()

    #  Here we'll create 12 of them evenly spaced apart
    for i in [0...12]
    #  Create a star inside of the 'stars' group
      star = @stars.create(i * 70, 0, 'star')

      #  Let gravity do its thing
      star.body.gravity.y = 6

      #  This just gives each star a slightly random bounce value
      star.body.bounce.y = 0.7 + Math.random() * 0.2

    #  The score
    @scoreText = @add.text(16, 16, 'score: 0', { fontSize: '32px', fill: '#000' })

    #  Our controls.
    @cursors = @input.keyboard.createCursorKeys()



  update: ->

    #  Collide the player and the stars with the platforms
    @physics.collide(@player, @platforms)
    @physics.collide(@stars, @platforms)

    #  Checks to see if the player overlaps with any of the stars, if he does call the collectStar function
    @physics.overlap(@player, @stars, @collectStar, null, this)

    #  Reset the players velocity (movement)
    @player.body.velocity.x = 0

    if (@cursors.left.isDown)
      #  Move to the left
      @player.body.velocity.x = -150
  
      @player.animations.play('left')

    else if (@cursors.right.isDown)
      #  Move to the right
      @player.body.velocity.x = 150
  
      @player.animations.play('right')

    else
      #  Stand still
      @player.animations.stop()
  
      @player.frame = 4

    #  Allow the player to jump if they are touching the ground.
    if (@cursors.up.isDown and @player.body.touching.down)
      @player.body.velocity.y = -350

  collectStar: (player, star) ->

    # Removes the star from the screen
    star.kill()

    #  Add and update the score
    @score += 10
    @scoreText.content = 'Score: ' + @score
  
new Game
Lastly, compile to javascript for use in your html. While you can use coffee-script on the browser side, it impacts load time.

Thursday, December 26, 2013

Upgrading Linux Mint Cinnamon from Olivia to Petra

My present to myself this year was a new operating system. I burned an .iso, wrapped it up, and put it under the tree (yes - I'm a big spender). I installed it today, upgrading my system from Mint 15 to Mint 16.

My laptop is an Inspiron model 3521. It's a basic i3 with 4 gb memory. It came with Windows 7, but I quickly fixed that, installing Linux Mint 15.

I started the upgrade this morning by creating a folder in my home directory named 'backup'. First I copied my .ssh folder into the backup. Then my .Webstorm config folder. That was the easy part. Then I started zipping up some if the bigger folders - ./Documents, followed by ./Pictures, and ./Desktop. And, I put all of these zips into my backup folder.

Now my projects - I zipped up my ./workspace folder, and my ./git folder. My git folder is all copies of projects on github, and as long as my pushes are up to date, I don't really need a backup, I can just git clone them. But then I'd need to visit project folders, running npm install, cake, make, etc. So zipping is really more convenient.

I also went to my ./Downloads, and copied the installs for applications I don't install with apt-get, like eclipse or various sdk's. This way, I know I'll have the same version when I start back up.

When I was one, I zipped my ./backup folder into one big zip, and copied that to my thumb drive. I also put it in dropbox, just in case. I decided to break for lunch - it says that 3gb will take about an hour to upload.

After lunch, I put i the distro, and rebooted. It took about a half hour to install Linux. The first thing I did after I logged in was to run the Update Manager and install the latest patches.

Then I plugged in my thumb drive, and unzipped all my files where I wanted to put them. That was easier said than done. And of course, the next thing I did was visit google to install chrome. The install crashed, saying that I had a corrupt file. Fortunately, I had a copy in the downloads I had backed up, so I installed using that, and continued on.

There were no other issues. All in all, it's the best upgrade experience I've had! And the result is well worth the effort.

Tuesday, December 24, 2013

Ya Sure, You Betcha - It's a Sortin' Huginn Pluginn

Or plugin. Anyway - Huginn plugin architecture is simple. You only need a module that exposes 1 function that accepts 1 parameter - the site object. Everything else is a property of the site object.

Plugins are called after all the site date, posts, and drafts have been loaded, and before any output has been processed. This makes the sort plugin almost trivial.

First, update config.yml with the sort parameters:

...
sort:
  src: posts
  by: date
  direction: asc
  dest: posts_asc
Next, copy the code to the _plugins folder:

module.exports = (site) ->

  by = site.sort.by ? 'date'

  #
  # Get the list of items to sort
  #
  site[site.sort.dest] = (item for item in site[site.sort.src])

  #
  # sort in descending or ascending order
  #
  site[site.sort.dest].sort switch site.sort.direction ? 'asc'
    when 'desc'
      (a, b) ->
        if a[by] < b[by] then 1 else if a[by] > b[by] then -1 else 0
    else
      (a, b) ->
        if a[by] > b[by] then 1 else if a[by] < b[by] then -1 else 0
Finally, we're going to add this fragment to our template:

...
{% for post in site.posts_asc limit: 5 %}
    
  • {{ post.title }}
  • {% endfor %} ...
    I use this to sort the game list on Katra

    (updated: to use google prettify rather than embedded gists. It makes it easier to focus on the code)

    Tuesday, December 17, 2013

    On, Hekyll! On, Jekyll! On Huginn and Muninn!

    My search for better blogging has led me to github static blogging. Dont get me wrong - Blogger is pretty good. But as a developer, I want more control over my content than Blogger allows.

    So I stared using Jekyll to post my blog. I absolutely love it. But I wanted more functionality, and that means plugins. And that means mucking around with ruby, and then generating the pages on my desktop. I'm not fond of running ruby on my laptop - it's slow. And I had to start learning ruby to get the plugins to work the way I wanted. And I had to make changes to Jekyll to test the site locally...

    You know, I got to thinking. This isn't what I want to be doing. And, since jekyll plugins can't run on github, I no longer have a requirement to use it ... I could make the pages manually if I were inclined. Or with my own site generator... Hey!

    Hence - Huginn is born. Huginn is a clone of Jekyll, but written in coffeescript. And my website is now easily tested and published to github using Huginn