Thursday, February 7, 2013

Crafty Tennis: A Component-Entity Game in JavaScript

Been dreaming of making a game for some time now and have been very interested in Component-Entity Systems which are a great way of keeping complexity down in a game.

I won't go through all the details here but suffice it to say you can keep complexity linear by either  adding new entities to your game (more "things" in the game) or by adding new components (more "functionality"). You then simply tell each new entity you add which components it has.


// Player Left (with AI)
Crafty.sprite(32, "img/padleft.run.png", {
  padleft: [0, 0]
});
Crafty.e("Paddle, 2D, DOM, Color, Multiway, Bound, AI, padleft, SpriteAnimation")
.color('rgb(255,0,0)')
.attr({ x: 20, y: H/2, w: 32, h: 32, player: 1 })
.bound({minX: 0, minY: 0, maxX: W/2, maxY: H})
.multiway(4, { W: -90, S: 90, D: 0, A: 180 })
.difficulty(3)
.bind('NewDirection', runner)
.animate('run', 0, 0, 5) // From x=0, y=0 to x=5 (6 frames)
;


Check it out on GitGub (cawoodm/tennis) or download it - it's actually quite fun to play!


Of course all this development was made possible by the excellent (and free) in-browser editor called Scripted - it's a poor man's Sublime Text.

Monday, January 7, 2013

Clean Your Path

Note: This is a Windows tip!

Each time you install new software, especially nerdy, developer stuff, it tends to add itself to your system PATH. For single .exe programs (e.g. curl or git) I find this wasteful so I've devised a cunning plan. Let's say you install curl.exe in C:\some\folder\curl


  1. Remove the folder from your system path
  2. Create a curl.cmd text file in C:\windows\system32
  3. Edit this text file and add the following: C:\some\folder\curl\curl.exe %*
Now, open a DOS window and run curl google.com - it works! How?

  • %* passes all parameters on to curl.exe
  • C:\windows\system32 is always on your system path
I recommend doing this for all your favorite command line programs and even your favorite editor. My new favorite is Scripted!

Wednesday, December 19, 2012

Easy MicroTemplating

I'm a huge fan of templates in that I always want to separate my view from my code. But I don't like to include hundreds of kilobytes of some library just to get templating - so I made my own in a few lines which I can just copy into any project.

The most basic usage is to pass it data and a template and get the result:
microTemplate({name:'Jack'}, '<h1>Hello {{name}}</h1>');
This will return:
<h1>Hello Jack</h1>

Now there are different ways of using it. You can specify a DOM element which contains your template so if you have this in your HTML:
<div id="op"><h1>Hello {{name}}</h1></div>
You can just do:
microTemplate({name:'Jack'}, $('#op')[0]);
This will automatically write the result back into your div.

It supports arrays so:
var friends = [{name:'Jack'},{name:'Jill'}];
microTemplate(friends, '<h1>Hello {{name}}</h1>', $('#op3')[0]);
Will result in:
<h1>Hello Jack</h1>
<h1>Hello Jill</h1>

If you want a table or an ordered list you'll need to specify header and footer:
microTemplate(friends, '<li>{{name}}</li>', $('#op4')[0], '<ol>', '</ol>');
Which will result in:
<ol>
 <li>Jack</li>
 <li>Jill</li>
</ol>

I think it's awesome!


<!doctype html>
<html>
<head>
  <script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
  <script>
  $(function() {
    microTemplate({name:'Jack'}, $('#op')[0]);
    microTemplate({name:'Jack'}, '<h1>Hello {{name}}</h1>', $('#op2')[0]);
    microTemplate([{name:'Jack'},{name:'>>Jill<<'}], '<h1>Hello {{name}}</h1>', $('#op3')[0]);
    microTemplate([{name:'Jack'},{name:'Jill'}], '<li>{{name}}</li>', $('#op4')[0], '<ol>', '</ol>');
  });
  
  function microTemplate(data, temp, el, head, foot) {
    if (typeof temp.innerHTML=='string') {el=temp;temp=temp.innerHTML;}
    data = [].concat(data);
    var res = head||'';
    for (var i in data) {
      res += temp;
      for (var f in data[i]) {
        res = res.replace(new RegExp('{{{'+f+'}}}', 'ig'), data[i][f]);
        res = res.replace(new RegExp('{{'+f+'}}', 'ig'), data[i][f].replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'));
      }
    }
    res += foot||'';
    if (el && typeof el.innerHTML == 'string') el.innerHTML = res;
    return res;
  } 
  </script>
</head>
<body>

<div id="op"><h1>Hello {{name}}</h1></div>
<div id="op2"></div>
<div id="op3"></div>
<div id="op4"></div>

</body>
</html>


Saturday, December 15, 2012

ssiJS: Server Side Includes on the Client

I cut my teeth on classic ASP where you build applications by including various blocks using SSI (server-side include) syntax. If you wanted to include common content (e.g. branding or a copyright statement) inside your <body> you would include it like this:
<!-- #include file="copyright.asp" -->

Aside from <iframe> there is no way to include content from other sites using HTML. You need JavaScript so I wrote a 3-liner jQuery script which does just that. Consider this HTML:
<div class="ssi" data-url="copyright.html"></div>

Add the following JavaScript to your $(function(){}); and you'll have client side includes:

$.each($('div.ssi'), function(a,b) {
$(b).load(b.getAttribute('data-url'));
});

What does this do? It iterates through all divs with the class 'ssi' and loads their content asynchronously from the url specified in their 'data-url' attribute. I think this is neat.

Full source:


<!doctype html>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.8.3.min.js"></script>
<script>
$(function() {
$.each($('div.ssi'), function(a,b) {
$(b).load(b.getAttribute('data-url'));
});
});
</script>
</head>
<body>
<div class="ssi" data-url="a.html"></div>
<div class="ssi" data-url="b.html"></div>
</body>
</html>

Tuesday, November 1, 2011

YQL: All the Data you can Eat

I love SQL and I love data. Just give me a database and some SQL and I'll analyse the bejeesuz out of it. I also like flexible interfaces. YQL provides all of this. The Yahoo Query Language is basically 2 things:
  1. A huge data source
  2. An easy query language which resembles SQL
  3. Standardized output format (JSON or XML)
OK, that was 3 things but I'm not going back to change my assertion just because I thought of an extra thing whilst typing. And, speaking of inaccuracies, I saaay "data source" but actually it's mostly just passing on data it gets from elsewhere. Let's dive in:

Say you wanna query an RSS feed:
SELECT * FROM rss WHERE url = 'http://sports.yahoo.com/top/rss.xml'

This will return the RSS items from the Yahoo! sports site. You can of course specify multiple feeds using IN (url1, url2) and you can also sort (example).

You can query weather, flickr for photos, find restaurants in San Francisco , list music videos ... I think you get the picture.

There is also the YQL Console, a place to test out your queries. It will generate the link which you can then use in your applications to query data. As you will see, you can specify the output format as XML or JSON:
http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20geo.oceans&format=json&callback=showOceans

The callback function wraps your data in a javascript function which means you just AJAX the URL above and your callback function will automatically be executed.

Finally the really gr8 thing about YQL is that it's free and it's cross-domain compatible. If you've ever made an application which fetches data from a different domain you'll know of the issues involved. Modern browsers just don't allow it unless the server says it's OK. YQL always adds the "it's OK header" (Access-Control-Allow-Origin: *) which means it damn well works. Very nice of dem folks at Yahoo!.

Finally, the other of the final 3 great things is that you can literally query (scrape) any web page on the, er, web. You can query normal HTML pages or XHTML or XML sources.

Coming soon, my jQuery Mobile RSS Reader app which uses YQL and Local Storage to save your RSS.

Sunday, September 11, 2011

SOAP2REST Proxy with node.js

Given the rebirth of JavaScript in the past decade it shouldn't surprise us that some wise-guy asked why we don't use the same language on the server as we use on the client: JavaScript!

Actually Microsoft was doing this in the 90's with their <script runat="server"> where you could write either VBScript or JScript both client and server side. Then browsers like Firefox took off and VBScript was unsupported leading to a rebirth of the powerful JavaScript language.

Node.js (or node.exe) is basically an interpreter like php.exe except you can actually use it stand-alone as it's own web service. You write a simple server.js like this:
var http = require('http');
var srv = http.createServer(function (request, response) {
  response.writeHead(200, {'Content-Type': 'text/html'});
  response.write("<h1>Hello World!</h1>");
  response.end();
}).listen(8080);
Next you run your script from the command prompt:
C:\node.exe server.js
Finally, open up your browser to http://localhost:8080 and you should see Hello World! in large, friendly letters.

Because I'm planning a killer hip mobile/offline app which consumes SOAP web services I decided to write a node.js script which will allow me to make simple HTTP GET requests and receive JSON data in return. The soap2rest.js proxy I wrote converts the GET request to a SOAP request and should parse the SOAP response to return JSON:
myApp.html -> HTTP GET -> (soap2rest.js) -> SOAP Request -> SOAP Response -> JSON

The first thing I need is an HTTP client. It's important to remember that our soap2rest.js is going to proxy the SOAP request so I made a generic HTTP request function:

function doHTTP(options, success, error) {

  var req = http.request(options, function(res) {
    var data = '';
    res.setEncoding(options.encoding || 'utf8');
    res.on('data', function (chunk) { data += chunk; });
    res.on('end', function () { success({ data: data, response: res }); });
  });

  if (typeof options.body != 'undefined') req.write(options.body);
  req.end();
  
  req.on('error', function(e) { error('HTTP ERROR: ' + e.message); });
}
As you can see the function simply takes all it's parameters via the options object and has two callback functions for success and error. Now all we have to do is map the incoming GET to an HTTP SOAP request. In order to make this proxy as generic as possible I defined the following syntax for the URL: http://whatever/service/method?parameters=values So, for a simple weather service I would call: http://localhost:8080/weather/fetch?city=Zurich Before I can call my soap2rest.js proxy I need to define the service call. This is done in a configuration file called fetch.json corresponding to the fetch method of my weather service. The configuration file sits in a folder called weather with other potential methods: weather/fetch.json:
{
 "url": "http://www.webservicex.net/globalweather.asmx?op=GetWeather",
 "headers": {
  "SOAPAction": "http://www.webserviceX.NET/GetWeather",
  "Content-Type": "text/xml"
 }
}
This configuration file tells SOAP2REST.js almost everything it needs to know about calling the SOAP service globalweather.asmx. What it still needs is the request format. This can be discovered by parsing the WSDL of the service but this is seriously complicated and liable to error. And I'm too lazy. So, the developer "just" has to provide the sample request body in fetch.xml inside the weather/ folder:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope  
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetWeather xmlns="http://www.webserviceX.NET">
      <CityName>##CITY##</CityName>
      <CountryName></CountryName>
    </GetWeather>
  </soap:Body>
</soap:Envelope>
The ##CITY## is a placeholder which will be replaced with the city parameter of the incoming GET request. Here is where the magic happens. The SOAP2REST function does the following:
  1. Parse the URL and determine the service and method
  2. Read the service/method.json configuration file
  3. Read the service/method.xml request file
  4. Replace all placeholders from the query string (e.g. city)
  5. Call the SOAP service POSTing the method.xml data
  6. Return the response to the client
So here's the magic SOAP2REST:
function SOAP2REST(URL, success, error) {

  URL = url.parse(URL, true);

  // Load Service Definition
  try {
    var soapJSON = fs.readFileSync('./soap' + URL.pathname + '.json', 'UTF-8');
  } catch (e) {
    return die({msg: "Service description " + URL.pathname + ".json could not be found!", err: e}, 404);
  }
  
  // Load SOAP Request
  var soapXML = '';
  try {
    soapXML = fs.readFileSync('./soap' + URL.pathname + '.xml', 'UTF-8');
  } catch (e) {
    // No problem
  }
  
  // Parse SOAP Configuration
  try {
    var soapJSON = JSON.parse(soapJSON);
 var soapURL = url.parse(soapJSON.url, true);
  } catch (e) {
    return die({msg: "Service JSON could not be parsed!", name: e.name, message: e.message}, 500);
  }
  
  // Set Parameters
  for (p in URL.query) soapXML = soapXML.replace('##' + p.toUpperCase() + '##', URL.query[p]);

  // Prepare SOAP Request Headers
  soapJSON.headers = soapJSON.headers || {};
  soapJSON.headers["Content-Length"] = soapXML.length;
  soapJSON.headers["Connection"] = "close";
  
  // Do SOAP Call
  var httpOptions = {
    host:     soapURL.hostname,
    post:     soapURL.port || 80,
    method:   soapJSON.method || 'POST',
    path:     soapURL.pathname,
    headers:  soapJSON.headers,
  };
  
  httpOptions.body = soapXML;
  
  doHTTP(httpOptions,
    function(d) {
      success(d);
    },
    function(e){
      error(e, 500);
    }
  );

}
Technically, I guess, this ain't REST because I'm not using /weather/fetch/city/Zurich/ but I prefer /weather/fetch?city=Zurich because this is the standard HTTP way of passing parameters and it means AJAX forms will work automagically!

If I do say so myself, I like the way you can easily add a new service on the fly simply by adding a .json and .xml file.

Now to find an XML2JSON converter...

Note: This code is all for node.js v5.6 and the functions seem to change with every release so no doubt this won't work in future! Full Source Code

Tuesday, August 30, 2011

Tinkering with Javascript Libraries on jsfiddle.net

Man I'm out of it. Such great tools that I missed during my post-2.0 slumber.

jsfiddle allows you to quickly and easily make and test JavaScript apps using some of the cool libraries out there (e.g. jQuery or mootools).

Just go to http://jsfiddle.net and start hacking in your HTML, Javascript and CSS. Press Ctrl+Enter to run and your app will, er, run!

I think it's cool.

Check out my sandbox application which says hello to you via ajax. Oh the wonders of modern technology.