Just summing up what Phobos Labs said as a picture.
Pixie Demo Video Roundup
Here’s some recent videos demoing the magically rapid prototyping of Pixie.
Array#extremes Useful JavaScript Game Extension #30
###* * Returns an object containing the extremes of this array. * * @param {Function} [fn] An optional funtion used to evaluate * each element to calculate its value for determining extremes. * @returns {min: minElement, max: maxElement} * @type Object ### Array::extremes = (fn) -> fn ||= (n) -> n min = max = undefined minResult = maxResult = undefined this.each (object) -> result = fn(object) if min? if result maxResult max = object maxResult = result else max = object maxResult = result min: min max: max
Usage:
[-1, 3, 0].extremes() # => {min: -1, max: 3}
test "#extremes", -> array = [-7, 1, 11, 94] extremes = array.extremes() equals extremes.min, -7, "Min is -7" equals extremes.max, 94, "Max is 94" extremes = array.extremes (value) -> value.mod 11 equals extremes.min, 11 equals extremes.max, 94
Array#wrap Useful JavaScript Game Extension #29
/** * Pretend the array is a circle and grab a new array containing length elements. * If length is not given return the element at start, again assuming the array * is a circle. * * @param {Number} start The index to start wrapping at, or the index of the * sole element to return if no length is given. * @param {Number} [length] Optional length determines how long result * array should be. * @returns The element at start mod array.length, or an array of length elements, * starting from start and wrapping. * @type Object or Array */ Array.prototype.wrap = function(start, length) { if(length != null) { var end = start + length; var result = []; for(var i = start; i < end; i++) { result.push(this[i.mod(this.length)]); } return result; } else { return this[start.mod(this.length)]; } };
Simple use:
[1, 2, 3].wrap(-1) => 3
[1, 2, 3].wrap(6) => 1
Or get fancy and tile your kitchen:
["w", "o", "o", "o"].wrap(0, 16) => ["w", "o", "o", "o", "w", "o", "o", "o", "w", "o", "o", "o", "w", "o", "o", "o"]
Array#clear Useful JavaScript Game Extension #28
Here’s a useful little method that empties out an array. Sure you could type myArray.length = 0;
but that is kind of weird. For some reason myArray.clear()
just makes more sense to me.
/** * Empties the array of it's contents. It is modified in place. * * @type Array * @returns this, now emptied. */ Array.prototype.clear = function() { this.length = 0; return this; };
The series continues…
Capistrano Rails: A group writable tmp directory
Maybe you’ve run into [out :: …] rm: cannot remove `/…/releases/20110221192810/tmp/restart.txt’: Permission denied
I did. The reason was because we were deploying with multiple users and when the tmp directory was being created it was not set to group writable.
Fortunately it is an easy fix, just add this into your cap deploy script:
after :deploy do run "chmod -R g+w #{release_path}/tmp" end
Valentine's Day Card
Here’s a simple visualization I made in Pixie using some music from Mike Williams.
Javascript String#constantize and String#parse – Useful Extensions 26 and 27
Here are two extensions to the String
class that I’ve found quite useful. constantize
and parse
. They are in CoffeeScript because JavaScript fills me with a growing disgust.
String::constantize = () -> if this.match /[A-Z][A-z]*/ eval("var that = #{this}") that else undefined String::parse = () -> try return JSON.parse(this) catch e return this
constantize
is based on the ActiveSupport method. It transforms a string that represents the name of a class into a reference to that class. It uses eval to accomplish this, but until JavaScript gets more extensive reflection capabilities it’s probably the best we can do.
Parse is a useful way to convert the string into a raw JavaScript type if possible, otherwise it returns just the string itself. For example if I have a string "false"
, "false".parse()
will return the JavaScript value false. Likewise '{"a": 7}'.parse()
will return a JavaScript object with a property a
that has the value 7
.
Pretty sweet.
jQuery Drag Image From Desktop Plugin
Here’s the CoffeeScript for a jQuery plugin I wrote that makes accepting images dragged in from the desktop super easy. The event.fix
part at the beginning is because jQuery currently doesn’t pass on the dataTransfer attribute of events. Once that’s taken care of we create the plugin.
(($) -> $.event.fix = ((originalFix) -> (event) -> event = originalFix.apply(this, arguments) if event.type.indexOf('drag') == 0 || event.type.indexOf('drop') == 0 event.dataTransfer = event.originalEvent.dataTransfer event )($.event.fix) $.fn.dropImageReader = (callback) -> stopFn = (event) -> event.stopPropagation() event.preventDefault() this.each () -> element = this $this = $(this) $this.bind 'dragenter dragover dragleave', stopFn $this.bind 'drop', (event) -> stopFn(event) Array.prototype.forEach.call event.dataTransfer.files, (file) -> imageType = /image.*/ if !file.type.match(imageType) return reader = new FileReader() reader.onload = (evt) -> callback.call(element, file, evt) reader.readAsDataURL(file) )(jQuery)
The plugin takes a callback that will be called when any of the matched elements receive an image file via the drop event. Here’s an example usage:
$(".tiles").dropImageReader (file, event) -> img = $ "", alt: file.name src: event.target.result title: file.name $(this).append img
For image drops all you really care about is the file name and the data url, but if for some reason you need different file results here’s the line to modify: reader.readAsDataURL(file)
. You can also extend or alter what is passed to the callback if this is too mundane for your needs.
And here’s the JS version for anyone eager to copy/paste:
(function() { $.event.fix = (function(originalFix) { return function(event) { event = originalFix.apply(this, arguments); if (event.type.indexOf('drag') === 0 || event.type.indexOf('drop') === 0) { event.dataTransfer = event.originalEvent.dataTransfer; } return event; }; })($.event.fix); $.fn.dropImageReader = function(callback) { var stopFn; stopFn = function(event) { event.stopPropagation(); event.preventDefault(); }; return this.each(function() { var $this, element; element = this; $this = $(this); $this.bind('dragenter dragover dragleave', stopFn); $this.bind('drop', function(event) { stopFn(event); Array.prototype.forEach.call(event.dataTransfer.files, function(file) { var imageType, reader; imageType = /image.*/; if (!file.type.match(imageType)) { return; } reader = new FileReader(); reader.onload = function(evt) { return callback.call(element, file, evt); }; reader.readAsDataURL(file); }); }); }); }; })(jQuery);
Happy image dropping!
Number#snap Useful JavaScript Game Extension #25
Well my friends, it’s been quite some time. So without further ado back to the series!
/** * Returns the the nearest grid resolution less than or equal to the number. * * EX: * (7).snap(8) => 0 * (4).snap(8) => 0 * (12).snap(8) => 8 * * @param {Number} resolution The grid resolution to snap to. * @returns The nearest multiple of resolution lower than the number. * @type Number */ Number.prototype.snap = function(resolution) { return (this / resolution).floor() * resolution; };
This handy method is useful for when you need to snap input to a grid (like in a tile editor).
I hope you enjoyed this installment of the wonderful 256 part series on JavaScript game extensions.