Tuesday, February 19, 2013

My js1k submission: Flurry

App: Flurry

In my second blog post I wrote about javascript golfing, and how it is a great way to entertain yourself and learn some cool tricks along the way. With js1k underway (you can submit till Match 31st), I have decided to write about my submission, Flurry. Now originally it was going to use both the Full Screen API, as well as the Pointer Lock API (Mozilla misspelled their call with a capital S in screen), however after submitting it turned out that webkit blocks (be default) the fullscreen/pointerlock from within a frame (which is how js1k hosts submissions). I was disappointed but moved on to a variant that didn't use those calls.

The final code came in at 1023 bytes, here is the original uncompressed source (4.8 kB):

 /*  
  * By: Zolmeister  
  * http://zolmeister.com  
  */  
 mouseX = mouseY = 0  
 flowers = []  
 // Z  
 letter = [[.3579, .1628], [.6421, .1599], [.3512, .7326], [.6488, .7297]]  
 onmousemove = function(e) {  
   mouseX = e.pageX  
   mouseY = e.pageY  
 }  
 cHi = c.height = innerHeight - 21  
 setInterval(function() {  
   if (mouseX) {  
     cWid = c.width = innerWidth - 21  
     //with with is with  
     with (a) {  
       with (Math) {  
         rand = random  
         //Align text so that it rotates cleanly  
         textBaseline = 'middle'  
         textAlign = 'center'  
         shadowColor = '#222'  
         if (rand() > .6 & flowers.length < 2) {  
           //spawn flower  
           flow = rand() * 27 + 10025  
           dir = rand() * PI * 2  
           flower = {  
             x : mouseX,  
             y : mouseY,  
             dir : dir,  
             xSpeed : cos(dir),  
             ySpeed : sin(dir),  
             flower : String.fromCharCode(flow), //unicode flowers  
             rot : 0,  
             poptime : 20,  
             size : 90,  
             color : '#' + ['FA7A79', 'A266AC', 'E38F3D', '81A63F', '619CD8'][~~(rand() * 5)]  
           }  
           flowers.push(flower)  
         }  
         for (i in flowers) {  
           with (flowers[i]) {  
             dir %= 2 * PI  
             //wall collision in radians
             if (x < 70 | x > cWid - 70) {  
               xSpeed *= -1  
               if (x < 70)  x = 70  
               if (x > cWid - 70)  x = cWid - 70  
             }  
             if (y < 70 | y > cHi - 70) {  
               ySpeed *= -1  
               if (y < 70)  y = 70  
               if (y > cHi - 70)  y = cHi - 70  
             }  
             x += xSpeed * 16  
             y += ySpeed * 16  
             last = letter[0]  
             for ( j = 1; j < 4; j++) {  
               x1 = cWid * last[0]  
               y1 = cHi * last[1]  
               x2 = cWid * letter[j][0]  
               y2 = cHi * letter[j][1]  
               m = (y1 - y2) / (x1 - x2)  
               yy = m * (x - x1) + y1  
               if (x < max(x1, x2) & x > min(x1, x2)) {  
                 if (abs(y - yy) < 10) {  
                   x -= xSpeed * 15.9  
                   y -= ySpeed * 15.9  
                   j=4  
                 }  
               }  
               last = letter[j]  
             }  
             rot += PI / 9  
             poptime -= 1  
             if (flowers.length < 150 & poptime < 0 && size && abs(x - mouseX) < size / 2 & abs(y - mouseY) < size / 2) {  
               size *= .9  
               poptime = 30  
               dir = rand() * PI * 2  
               xSpeed = cos(dir)  
               ySpeed = sin(dir)  
               for ( i = 0; i < 10; i++) {  
                 dd = rand() * PI * 2  
                 xx = mouseX + cos(dd) * 45  
                 yy = mouseY + sin(dd) * 45  
                 flowers.push({  
                   x : xx,  
                   y : yy,  
                   xSpeed : cos(dd),  
                   ySpeed : sin(dd),  
                   dir : dd,  
                   flower : String.fromCharCode(rand() * 27 + 10025), //unicode flowers  
                   rot : 0,  
                   poptime : 20,  
                   size : size,  
                   color : '#' + ['FA7A79', 'A266AC', 'E38F3D', '81A63F', '619CD8'][~~(rand() * 5)]  
                 })  
               }  
             }  
             //draw rotated flower  
             font = size + 'px sans'  
             shadowBlur = 3;  
             fillStyle = color  
             save()  
             translate(x, y)  
             rotate(rot)  
             fillText(flower, 0, 0)  
             restore()  
           }  
         }  
       }  
     }  
   }  
 }, 33)  

I would like to point out some of the most useful things I used to save bytes in this, namely using the javascript 'with' call, along with ~~, &, |.  ~~ is used to convert a float to an integer, and the binary operators were used to replace the traditional 'or' (||) and 'and' (&&). The binary operators don't work in all cases however (from my experience it works with boolean expressions but not 'truthy' values (ie, strings or numbers !=0). The real gem in the code however is the rampant use of the 'with' call. I make a  lot of calls to the canvas context (as well as math operations sin, cos, abs) and also within loops to object properties. I was surprised to find out that you can assign values such as 'shadowBlur=3' within a 'with' block and have it work out nicely.

Other than that, the only thing worth noting is that if you want to get spinning text (in my case unicode) its easiest (and the only way I got to work) to set the textBaseline='middle' and textAlign='center' on the canvas context. This positions the text (nearly) perfectly so that it rotates flawlessly. Without that, you get weird circulating objects (which is what happens to objects that are spun offset from their center).

Finally, after hand minifying my code by renaming variables and moving a few bits of code around accordingly and also shortening 'if' blocks with ternary operators, I passed the code first through the google closure compiler service and then through JSCrush. This gave me a tidy line of 1023 bytes and concluded my js1k submission.

 _='X=Y=0;D=[];G=[[ 358`16 2`16 [ 351`73 9`73]];onmousemove= b X X;Y Y};K=c.hQZHQ-21;setIn rval(  if(X J=c.wid!ZWid!-21; a) Ma!) i   M=random, xtBasel e="mikle  xtAlign="cen r  Color="#222  6< &2 &$ ,     Xq:Y,N:N,A: $ B:z$) 90  D) D[i] N%=2*PI; >x|x>J A x (x=  x>J x=J- )  >y|y>K B y (y=  y>K y=K- ) x+?6*A;y+?6*B;P=G[0]; j?;4>j;j++)T=J*P[0 V=K*P[1 U=J* [0 W=K* [1 R=(V-W)/(T-U)*(x-T)+V,x<max^&x>m ^ 10> y-R) (x Aq B,j=4 P= ;O+=PI/9;F-?;if(150 0>F H  x-X_& y-Y_ H*= 9;F=30;N ;A= $ B=z$  i=0;10>i;i++)k ,L=X+45*  R=Y+45*z      Lq:R,A:  B:z N:k H }font=H+"px sans"; Blur=3;fillStyle=I;save( transla (xq rota (O fillText(E,0,0 restore()}}},33) ,I:"#"+["FA7A79@A266AC@E38F3D@81A63F@619CD8"][~~(5* )]}) ,E:Str g.fromCharCode(27* +10025 O:0,F:20,H: =2* *PI -  ( (k  0. in >D.leng!&     D.push({x: 70 wi!( function( ); ],@, ), && M() cos for( G[j] abs( =b.page *=-1, > -?5.9* te 3 [ 64 shadow ){!th$(N?=1@ "QeightZ= ner^(T,U)_)<H/2`, kddq,yzs ';for(Y=0;$='zqk`_^ZQ@?$!                                 '[Y++];)with(_.split($))_=join(pop());eval(_)  



Monday, December 10, 2012

How to deploy node.js applications


I am currently running 5 websites on my free (1 year) Amazon EC2 micro instace. Every one of these urls corresponds to a separate node.js service running on the server:
http://zoggle.zolmeister.com/
http://games.zolmeister.com/
http://avabranch.zolmeister.com/
http://gallery.zolmeister.com/
http://charityvid.org/

Let me preface this by saying that the way I deployed my sites before was the following:
  • ssh myserver@amazonec2
  • screen -ls (to display all the screen instances I had open)
  • screen -r XXXX (guess at which screen was the one running the site I wanted to update)
  • node app.js (launch a server process in the screen, and then Ctrl+a+d to detach from the screen)
This is obviously inefficient and slow, and by the time I got to running 5 websites (and 1 proxy service to direct traffic) I decided I needed a more efficient way of deploying and managing my sites.


Enter upstart, the /sbin/init replacement. Upstart lets you maintain just one config file per site and start and stop it as a service without the need to run everything in a screen. To deploy an app is as simple as copying the myapplication.conf file into /etc/init/ and running "start myapplication". Here is an example of one of my conf files (modified from this site):

 description "CharityVid node server"  
 author   "Zolmeister"  
 stop on shutdown  
 respawn  
 respawn limit 20 5  
 # Max open files are @ 1024 by default. Bit few.  
 limit nofile 32768 32768  
 script  
      echo $$ > /var/run/charityvid.pid  
      export NODE_ENV=production  
      cd /home/pi/websites/charityvid  
      exec /usr/local/bin/up -p 3100 -w app.js 2>&1 >> /var/log/charityvid.log  
 end script  

What this conf file says is that on service start, log the process's pid (in case we need to kill it), set node to production mode, cd into the site directory (this is necessary because of issues with express.js template loading), and finally start the app. Notice that I start the app with the "up" command, and that I am piping 2>&1 (std err to std out) and appending (>>) it to the log file. The "up" command comes from the up node module which does auto-updating and load balancing. The alternative to "up" is node-supervisor which doesn't do load balancing but can be run on any application out of the box (without the modification required by "up").

Ok, so now we have a way to start all of our applications, but how to route all the connections to the right place (remember all our apps are on one server with one IP address). Normally you would use NGINX (pronounced "engine x"), but the stable branch doesn't support websockets (used by http://zoggle.zolmeister.com) so I decided to go with the simple node-http-proxy module. The documentation is a bit lacking, but I was able to get all the sites routed, including websockets support and ssl support (for https://charityvid.org/). Here is what my app.js file looks like for my "gateway" application:

 var http = require('http'),  
      httpProxy = require('http-proxy'),  
      fs = require('fs'),  
   https = require('https'),  
   crypto = require("crypto"),  
   path = require('path');  
 var main1 = httpProxy.createServer({  
  router: {  
   'zoggle.zolmeister.com': 'localhost:3001',  
   'avabranch.zolmeister.com': 'localhost:3005',    
   'charityvid.org': 'localhost:3100'  
  }  
 });  
 main1.listen(8000);  
 var proxy = new httpProxy.HttpProxy({  
  target: {  
   host: 'localhost',  
   port: 8000  
  }  
 });  
 var server = http.createServer(function (req, res) {  
  // Proxy normal HTTP requests  
  proxy.proxyRequest(req, res);  
 });  
 server.on('upgrade', function(req, socket, head) {  
  // Proxy websocket requests too  
  proxy.proxyWebSocketRequest(req, socket, head);  
 });  
 server.listen(80);  
 function getCredentialsContext (cer) {  
  return crypto.createCredentials({  
   key: fs.readFileSync(path.join(__dirname, 'certs', cer + '.key')),  
   cert: fs.readFileSync(path.join(__dirname, 'certs', cer + '.crt'))  
  }).context;  
 }  
 var certs = {  
  "charityvid.org": getCredentialsContext("charityvid")  
 };  
 var options = {  
  https: {  
   SNICallback: function(hostname){  
    return certs[hostname];  
   }  
  },  
  hostnameOnly: true,  
  router: {  
   'charityvid.org': 'localhost:3100'  
  }  
 };  
 // https  
 httpProxy.createServer(options).listen(443);  

After running the routing proxy every site should now be functional and up, but we still have to ssh into the server to start/stop apps and to update them (with supervisor and up you should rarely have to restart the node server). This is where fabric comes in. Fabric lets you automate the ssh process and run commands on the server from your work machine. For example a simple command to send the initial application.conf upstart file would be:
 def installInit():  
      put('avabranch.conf', '/etc/init/avabranch.conf', True)
      sudo('touch /var/log/avabranch.log')  
      sudo('chown admin /var/log/avabranch.log')  

And if you're using git to manage your source (I store mine in a private bitbucket repo), updating your production code is as easy as "fab update:avabranch" with the following fab file declaration:
 def update(app):  
      with cd('/home/admin/websites'):  
           if app=="avabranch":  
                run('cd avabranch && git pull')   

Finally I keep my sites behind the Cloud Flare service, which basically means that they are protected from DDOS attacks, plus get free and efficient localized caching (cloud flare has many data-centers all over the world, which allows them to improve site cache latency times).

Monday, November 19, 2012

Avabranch

Avabranch

Avabranch (source on Github) is my entry for the github gameoff web-game challenge. It's built using Node.js and the Express framework, though most of the code is pure handwritten client-side javascript. I really enjoyed working on avabranch and wanted to take you through what I did to build it.

First of all, since the game uses canvas, we need to figure out how to clear, update, and draw our objects on the canvas. This is where 'requestAnimFrame' comes in. The boilerplate code for this function is this (it adds support for browser-specific implementations because it's not a finalized standard yet):

 window.requestAnimFrame = (function() {  
      return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||  
      function(/* function */callback, /* DOMElement */element) {  
           window.setTimeout(callback, 1000 / 60)  
      }  
 })()  


Before we call this function however, we need to add things that need to be drawn. For me, I add a player, enemy spawner, hud, and powerup spawner to the game object, and then call the update function on the game object.

 function startGame() {  
      keyListeners = []  
      game.play = false  
      game = new Game(canvas)  
      var player = new Player(game, null, null, null, game.speed)  
      var spawner = new BlockSpawner(game, game.speed)  
      var hud = new HUD(game)  
      var power_spawner = new PowerupSpawner(game)  
      game.addObject("spawner", spawner)  
      game.addObject("player", player)  
      game.addObject("power_spawn", power_spawner)  
      game.addObject("hud", hud)  
      game.update()  
 }  

Now, when I call game.update(), it runs this code:
 this.update = function(time) {  
           if (!this.play)  
                return;  
           this.timeDelta = time - this.prevTime  
           this.prevTime = time  
           if (isNaN(this.timeDelta)) {  
                requestAnimFrame(this.update.bind(this))  
                return  
           }  
           this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)  
           this.physics(this.timeDelta)  
           this.draw()  
           requestAnimFrame(this.update.bind(this))  
      }  

This is where most new developers make a mistake, as they forget the critical 'time' variable that is passed into the function by requestAnimFrame, which is essential for consistent playback across all machines. In order to make sure that a slow machine, unable to run the game at the optimum 60 fps, doesn't end up playing a game that runs half as fast we must keep track of how much time has passed since we last updated the objects on the screen. This is what 'timeDelta' is for, as it keeps track of this time. Now when the Game object calls the 'physics' function on all of its children, it passes in this timeDelta value which is used in the update code for objects that move. For example the 'Line' object uses timeDelta when it updates its position:

 this.points[i].y += .05 * timeDelta * this.ySpeed  

Another thing that is important for gameplay is managing key state and key events. I actually ended up writing my own key event system for this. The basics of how I manage the keyboard are that I store all pressed keys in a JSON object, and on keypress I loop through any listeners that were listening for that keypress and run whatever function they passed in. Here is the code for that (the keys are converted from key number to letter for access in the dictionary):

 var keyListeners = []  
 var keyState = {};  
 var keyMap = {  
      13 : 'enter',  
      37 : 'left',  
      38 : 'up',  
      39 : 'right',  
      40 : 'down',  
      186 : ';'  
 };  
 window.onkeydown = function(e) {  
      try {  
           keyState[keyMap[e.which] || String.fromCharCode(e.which)] = e.which;  
      } catch(e) {  
           console.log('error converting keypress to char code')  
      }  
 }  
 window.onkeyup = function(e) {  
      try {  
           delete keyState[keyMap[e.which] || String.fromCharCode(e.which)];  
      } catch(e) {  
           console.log('error deleting keypress to char code')  
      }  
 }  
 window.onkeypress = function(e) {  
      for (var i = 0; i < keyListeners.length; i++) {  
           var k = keyMap[e.which] || String.fromCharCode(e.which)  
           if (keyListeners[i][0] === k) {  
                e.preventDefault()  
                keyListeners[i][1]();  
           }  
      }  
 }  

The last thing I want to mention is the code that I used to draw the lines. At first my approach was to draw a ton of dots as fast as I could to make it seem linear. This worked but was too CPU intensive, so I decided to try and come up with a better way to do it. I found out that you can draw lines on the canvas easily, and better yet it natively supports rounded caps. The problem was that before when you turned it was smooth, but now the edges were sharp. I tried to solve this by keeping track of the slope of the line, and when the slope changed then I would use the canvas 'quadraticCurveTo' method to round out the corner. This did not work well and so I continued to look for a solution. Turns out that canvas also lets you set the line joint type to round. Yeah, that was quite a journey, but I'm happy I got it working the way I wanted to. Here is the code:

 this.draw = function(ctx) {  
           var tail = this.points[0]  
           var head = this.points[this.points.length-1]  
           if(!tail || !head)  
                return  
           ctx.beginPath();  
           ctx.lineWidth=head.r*2  
           ctx.lineCap='round'  
           ctx.lineJoin='round'  
           ctx.moveTo(tail.x,tail.y);  
           ctx.strokeStyle = tail.color  
           for (var i = 1; i < this.points.length; i++) {  
                var point = this.points[i]  
                ctx.lineTo(point.x,point.y)  
           }  
           ctx.stroke();  
           ctx.closePath()  
      }  

Wednesday, October 24, 2012

Back-light Music LEDs


Cameras don't like taking pictures in the dark.
tl;dr
The LED lamp behind my monitor pulsates with the audio from my computer. Video is at the bottom.
The Code (warning, ugly code ahead)
Setup:
So the way the led lamp works, is that it is hooked up to an arduino which connects over USB to my tower. My computer is running a python script which sends the arduino the value of brightness to set the lamp at, based on the audio output of the music.

PulseAudio -> python -> arduino -> LED lamp

Getting the audio output into python:
This was probably the most silly issue that I had to deal with, because it seemed so simple in terms of what I needed to do, but took a ton of trial and error and lots of failing. Let me save you the trouble. You may have heard of JACK. JACK is a pain, takes a lot of work, and for me it didn't work at all. Save yourself the trouble and stay away from JACK. I use PulseAudio for my sound system as it works  with my USB headphones (they're virtual 7.1 surround sound and have drivers that only work on windows XP). Setting up my headphones is a pain, but worth it because of the fuzz (the part that goes over my ears is fuzzy which makes them extremely comfortable). Ok, enough background, here is the secret:

  • Open Pulse Audio Volume control (pavucontrol).
  • Open Sound Recorder.
  • Start recording, and go to the "Recording" tab of the volume controller
  • Click on the input, and change it to "Monitor of XXX" (where XXX is your audio device)
  • Done! (Just remember to do this for the python script while running it for the first time)
Python and beat detection:
You can check out the code here. Basically it uses the pyaudio library to record audio, write streaming data chunks to a temporary wav file (this could be improved upon), and use some magic to get amplitude data from the wav file. Then it normalizes the amplitude over the 0-255 range of LED brightness for the arduino, smooths the curve slightly, and sends the amplitude over to the arduino at 115200 baud (not sure if this is too much/not enough, but it worked for me - 9600 baud hung because it was too slow).
Beat detection snippet (thanks Mr.Doob and Dean McNamee)
 w = wave.open(WAVE_OUTPUT_FILENAME, 'rb')  
     summ = 0  
     value = 1  
     delta = 1  
     amps = [ ]  
     for i in xrange(0, w.getnframes()):  
       data = struct.unpack('<h', w.readframes(1))  
       summ += (data[0]*data[0]) / 2  
       if (i != 0 and (i % 1470) == 0):  
         value = int(math.sqrt(summ / 1470.0) / 10)  
         amps.append(value - delta)          
         summ = 0  
         tarW=str(amps[0]*1.0/delta/100)    
         sendVal(tarW)#this method normalized the data and sends it to the arduino
         delta = value  

My normalization algorithm for the value consists of storing the last 100 values of data and dividing new data by the max of the last X values (all values before a reset) to get a value between 0 and 1, which I then multiply by 255 to get 0-255. After a period of low values (ie. silence), detected by the store of last 100 values, the minimum and maximum values reset to allow for a new song which may not fit the amplitude of the previous song. I smooth the data by averaging the current point with the previous point.

Arduino LED fading (pwm):
So the arduino UNO that I have has 6 pwm digital I/O pins, which allows me to dim LEDs attached to those pins. After that, just running an analogWrite() on them with a value between 0-255 will dim the LED accordingly. One thing I did have trouble with though was sending the 0-255 number over serial from python, which I fixed by using a buffer and made the python always write out 3 character strings of data and used the atoi() command (ascii to int) to get the values back out.

The lamp:
I hooked up 12 LEDs, 6 pairs of 2 LEDs hooked up in parallel connected to one of six pwm I/O pins. After lots of frustration regarding the illumination of the LEDs (I used a dremel to diffuse the LEDs, and ended up arcing them as shown below), I finally got it to work. I just can't let the arduino fall off because the wires going to it come out easily (design issue, but hey it works).

The result:
(yes I have 5 monitors, song: Bopalong, Kinobe)

Wednesday, September 26, 2012

My Favorite Exploit


XSS (Cross Site Scripting) is my personal favorite security hole. It's everywhere, on almost every site, and it's fun to exploit! I used to spend my evening scouring the top 500 sites on alexa for XSS vulnerabilities just for fun. In addition to that I did most of my testing manually. There are tools built to automate most XSS vulnerability tests, but that's no fun. This hacking spree taught me the foundations of JavaScript and web development in general. By developing intricate tunnel exploit schemes I learned so much about how the web operates at the user level and how bugs enable hackers to get in.

My endeavours got my name here: Google Security Hall Of Fame

Which led me to create this: http://gallery.zolmeister.com/ (click the page)

That page is my XSS gallery. The images are the websites favicons, with size relative to their ranking. I have saved nearly every one of the XSS vulnerabilities I have found by hand, which is now over 200. Most of the sites are ones that were unhelpful or just pissed me off in general and so I took a few minutes to find an XSS vulnerability in them (I almost never report these vulnerabilities). Some however (the big icons) are ones where I started at the top of a list of most popular sites and moved my way down, collecting vulnerabilities along the way. It's pretty scary actually, knowing that even the most high profile sites are vulnerable.

Saturday, September 8, 2012

How not to write a massively multi-player game

Welcome to Page Explorer!

Click here to join! (no longer up)
Click here (again) to join! (yes, bug)
Now hit the CAPS LOCK key (to toggle view state)
After you have joined here are the controls:

  • Ctrl = Jump
  • arrow keys = move
  • Down = Descend a level
  • Ctrl + up = pull up
  • CAPS LOCK = toggle game (visible/hidden)
  • T = chat (just start typing and the text will appear top-left, then enter to submit)
Want to explore somewhere else? Drag this link: Page Explorer to your bookmarks bar, then click on it when your on the site you want to join (may have to click it twice, also chrome blocks it in https pages).

"Wow this is so cool! How can I get the source?" - on github!

Alright, lets break it down!
A few words of warning before I begin, this game is one of my most poorly written and broken games of all. This was a great learning experience in what not to do with a game, and I hope that you will learn something too.

First let me explain how this app works on a general level.
  1. User injects script onto page
  2. script loads all the assets
  3. all assets load
  4. script connects using Socket.io to the master Node.js server
  5. The server puts the user in a room based on the website they're on
  6. users position, name, and animation state are sent to the server
  7. server relays info to all clients in room
  8. GO TO 6
This part actually makes sense, and what makes Page Explorer cool is that you can run it on any page you want. This also happens to be what makes it fail, due to different page layouts of the same site from different users makes them appear to float in mid air and other such bugs which are largely out of my control.

Ok lets start at the beginning of the code (or rather the first part that I wrote and where things wen't horribly wrong). I decided to write a skeletal animation system. Those look like this:
Basically a bunch of nodes connected to each other. This allows me to draw the player once and animate him freely. If you're confused, this video might help: http://www.youtube.com/watch?v=34cBGjCKkgU

The first step in skeletal animation is creating a skeletal map (here is where I messed up). Here is what mine looks like:

The issue here is that everything is absolute positioned instead of being relative to one another. The correct way to do it would have been to use a Polar system (angle, distance) instead of a Cartesian system (x,y).

 var skeleton=[{  
   "name": "root",  
   "rot": 0,  
   "x": 279,  
   "y": 266,  
   "skin": {},  
   "parent": -1,  
   "id": 0,  
   "children": [6, 7, 8]  
 }, {  
   "name": "head",  
   "rot": 0,  
   "x": 282,  
   "y": 150,  
   "skin": {  
     "self": {  
       "name":"head",  
       "x":0,  
       "y":-20  
     },  
     "bone": "neck"  
   },  
   "parent": 6,  
   "id": 1,  
   "children": []  
 },...  

My next step was creating an editor, in order to create everything (ie, draw the bones and connections and add skins etc.). Problem was that I was lazy. I ended up hard-coding the base skeletal system and the animation system involved saving a skeletal state to localstorage when done. There was no "undo" button, and I couldn't edit multiple animations at a time. To get it into my code I copy pasted the giant list of skeletal positions into my source. This is where spending just a bit more time in creating a good editor would have saved me tons of work. (I could post the source for my editor but i'd rather not... it's hideous).

My next mistake was in separating the user (you) from everybody else. I had to duplicate everything (physics, drawing, etc) in my code (that's bad - never duplicate code). This also caused me to keep all of the game code related to the player in one file (main.js - 651 lines) and then duplicate it in another file (socket.js - 173 lines). Yes, main.js should not contain all the code that it does and it was an absolute pain to debug.

My animation sequence seems ok at first, but it is definitely broken. Here is what it looks like:

 function movePlay(){  
   if(playQueue.length<2){  
     playing=false;  
   }  
   else if(sameFrame(playQueue[1],playQueue[0])){  
     playQueue.splice(0,1);  
     updatedQueue();  
   }  
   else{  
     for(var i in playQueue[0]){  
       var curS=playQueue[0][i];  
       var tarS=playQueue[1][i];//have to align within 60 frames  
       var xDistance=curS.x-tarS.x;  
       var yDistance=curS.y-tarS.y;  
       var rotDistance=curS.rot-tarS.rot;  
       var framesLeft=10-currentFrame%10;  
       if(curS.x!=tarS.x)  
         curS.x+=xDistance/framesLeft*-1;  
       if(curS.y!=tarS.y)  
         curS.y+=yDistance/framesLeft*-1;  
       if(curS.rot!=tarS.rot)  
         curS.rot+=rotDistance/framesLeft*-1;  
       if(framesLeft<1){  
         curS.y=tarS.y;  
         curS.x=tarS.x;  
         curS.rot=tarS.rot;  
       }  
     }  
   }  
 }  

The basis for this animation function is that it takes at least 2 frames (states of skeletons) and then motion-tweens them by one step when it's called. The issue (if it wasn't obvious) is that it doesn't support speed-change in tweens. This means that lets say I wanted the player to punch really fast (1 frame fist back, next frame fist forward), it would play really slow because my play-rate (10 steps - var framesLeft=10-currentFrame%10;) is constant. From one frame to the next is always the same amount of time. Instead, it should be set by the editor and be a value in the animation sequence (# steps the animation should take).

Another issue (which I didn't realize till too late) was my abundant use of global variables (maybe my separate var.js file should have given me a hint).

 player.height=500;  
 player.width=500;  
 var playC=player.getContext("2d");  
 var selectedBone;  
 var assetsList=["head", "left arm", "left foot", "left forearm", "left hand",   
 "left leg", "left thigh","neck","right arm","right foot","right forearm",  
 "right hand","right leg","right thigh","spine", "joint","joint2","none",  
 "hat1","hat2","hat3","hat4","hat5","hat6"];  
 var keysPressed=[];  
 var assetCount=0;  
 var assetCallback;  
 var assets={};  
 var playQueue=[];  
 var name=localStorage.name||prompt("name?");  
 localStorage.name=name;  
 var chats=[];  
 var hidden=true;  
 var chatting=false;  
 var currentChat="";  
 var passingThrough=false;  
 var others={};  
 var myHat=Math.floor(Math.random()*6)+1  
 var bgCtx=bgCanvas.getContext("2d");  
 var currentFrame=0;  
 var locked=false;  
 var showBone=false;  
 var jumping=true;  
 var climbing=false;  
 var grav=1;  
 var deltaTime=0;  
 var blocks=[];  
 var lastTimestamp=Date.now();  
 var me={  
   x:0,  
   y:0,  
   width:100,  
   height:100,  
   dir:"right"  
 }  

The solution to this is simple enough. I should have created a Game class which had these values associated with it, as well as separating values that control game state (ie. passingThrough, chatting, hidden etc.) from values controlling player state (jumping, climbing etc.).

Well, I hope that you found something useful in all that I did wrong. Bottom line is Don't Half-Ass Your Code. Do it right from the start (never say "I'll fix it later" or "I'll get back to it eventually" - especially in the beginning).

Cheers!

Tuesday, June 26, 2012

Javascript Golfing



 +

  
What is Javascript Golfing?
Well, Javascript golfing is the process of writing the smallest amount of javascript code to do something awesome. It tests your ability to reduce, reuse, and recycle for the purpose of achieving the tiniest footprint possible. Also, it's fun!
Note: All of these games and more can be found here: Games.Zolmeister.com

First attempt, Snake:
My first attempt at golfing was inspired by MXSnake (back when I didn't even know it was called golfing). Here is my version: tinySnake (686 bytes). Kind of large, not too pretty and nothing really special, except my key events which I think are quite unique.

 onkeydown=function(a){  
 q=a.which-38;  
 q%2?n=0:n=q-1;  
 q%2?e=q:e=0  
 }  

I realized that the key presses should be directly tied to the movement variables of the snake, so I used the keyCode itself to set the movement (I think it could be done even more elegantly, but it's a start).

Second attempt, Pong:
My second attempt at golfing was inspired by an article on hacker-news I read about, where someone made tron in 219 bytes(!). Instead of trying to best them though, I made Pong (451 bytes) instead. (Screen is blank until you hit a key, W and A for p1 movement and UP and DOWN for p2 movement) Sadly I don't have the original non-compressed code, but my technique for compression mimicked the tron game.

Third Attempt, Two Towers:


After feeling good about my pong implementation, I decided I wanted to make something new and original. I settled on a game where the player spawns objects to attack an enemy base. Another constraint I wanted to have was to keep it below 1KB (it's 1008 bytes currently), so that it could be compared to the applications at http://js1k.com (definitely check this out, there are some truly amazing apps people created). This time I did not lose the original non-compressed source:

 //chrome auto-generates accessors for objects with ids  
 <body><canvas id=c width=700></canvas>Buy:  
 <script>  
 C=c.getContext('2d')  
 money=time=level=1//multiple assignments in one statement reduces the use of semicolons  
 upgrade=.99  
 R=Math.random;//assign common functions to variables  
 enemies=[{size:50, x:650, speed:-1/1e99}]//use e for large values (1e3=1000) - saved 1 byte  
 friendlies=[{size:50, x:70, speed:0}]//use unique variable names for easy hand-minification  
 C.fillRect(0,0,c.width,c.height);  
 part1="<button onclick='";  
 part2="</button>"  
 doc=document  
 for(i=3;i<10;i++)  
      doc.write(part1+"buy("+i+")'>$"+i*10+part2);  
 //using ~~ instead of parseInt helps a lot  
 doc.write(" Upgrade: "+part1+"upgradeValue=~~(200/upgrade-200)*10+100;money-upgradeValue<0?i:(upgrade-=.05,money-=upgradeValue);this.innerHTML=upgradeValue'>"+upgrade*100+part2);  
 //keep functions to a minimum (the word function is expensive)  
 //the function below gets removed and the whole thing inserted in an onclick event  
 function buy(n){  
      n=n/upgrade*10  
      money-=n*upgrade;  
      money<0?money+=n:friendlies.push({size:~~(Math.pow(n,2)/250)+5,x:100,speed:60/n});  
 }  
 function animation(){  
      if(R()<.03)//AI code (random is your friend)  
           enemies.push({size:~~(R()*level)+7, x:650, speed:-(level-R())})  
   C.clearRect(0,0,700,300);  
   C.fillText("$"+~~money,9,9)  
   //concat both friendlies and enemies for updating the objects (drawing and moving)  
      g=[].concat(enemies,friendlies)  
      for (i in enemies){  
       for (j in friendlies){  
            //during minification, && and || can usually be replaced by & and | respectively  
        if(friendlies[j].x+friendlies[j].size>=enemies[i].x-enemies[i].size && enemies[i].size>0 && friendlies[j].size>0){  
         --friendlies[j].size<0?friendlies[j].size++:i;  
         enemies[i].size==1?money+=enemies[i].size:i;  
         --enemies[i].size<0?enemies[i].size++:i;  
         enemies[i].x-=enemies[i].speed;  
         friendlies[j].x-=friendlies[j].speed;  
         }  
       }}  
      for (i in g){  
                g[i].x+=g[i].speed  
                //I used negative speed values to differenciate between enemies and friendlies  
                C.fillStyle=g[i].speed<0?'#F10':'#10F';  
                C.save()  
                time+=.01  
                C.translate(g[i].x,150-g[i].size)  
                C.rotate(time*(g[i].speed<0?-1:1))  
                C.font=g[i].size+'pt txt';  
                //thanks http://js1k.com/2010-first/demo/750 for the inspiration to use unicode  
                C.fillText(String.fromCharCode(1161),g[i].size/2,g[i].size/2)  
                C.restore()  
           }  
      //inline if statements are better if doing one action  
      //friendlies[0].size==0?history.go():i;  
      //function are special  
      friendlies[0].size==0&&history.go();  
      //regular ifs are more eficient for more than 1 call  
      if(enemies[0].size==0)friendlies=[friendlies[0]],enemies[0].size=50,level++,money+=500;  
       money+=.25;  
       time+=.1  
 }  
 //put the function inside of quotes in the interval call later to save space  
 setInterval(animation,50)  
 </script>  

Finally, here are some tips for golfing:

Look at other peoples code. They come up with interesting tricks like this one (to remap the canvas calls to have shorter names):
 for($ in C=c.getContext('2d'))C[$[0]+$[6]]=C[$];  
-Source: Bouncing Beholder (This game is crazy-good, worth reading through the source)
Check out this tutorial on stackexchange.
Use a tool like jscrush after you hand-minify your code (and check that closure compiler won't help).
Good Luck!