jueves, 18 de septiembre de 2014

45 lineas de Javascript hacen un pianito

El API de Web Audio esta como pidiendo que alguien haga algo con eso, ofrece infinidad de posibilidades, es mas o menos nueva pero posiblemente lo suficiente madura para poder empezar a probar cosas con eso (para mis informacion ver la tabla de compatibilidades)

Por ahora las teclas son Z, X, C, V.. etc... Codigo fuente:
(function() {

    var audio = new window.webkitAudioContext();
    var oscillators = {};

    function createOscillator(freq) {
        var osc = audio.createOscillator();

        osc.frequency.value = freq;
        osc.type = "square";
        osc.connect(audio.destination);
        return osc;
    };

    var frequency = function(notenum) {
        return 293.66 * Math.pow(2, notenum/12);
    };

    var keyCodeToNote = {90: 'C', 88: 'D',  67: 'E', 86: 'F', 66: 'G', 78: 'A', 77: 'B'};
    var noteToNum = {C: 0, D: 2, E: 4, F: 5, G: 7, A: 9, B: 11};
    document.getElementById("pianito").onkeydown = function(e) {
        var osc = oscillators[e.keyCode];
        if (osc) return;

        var note = keyCodeToNote[e.keyCode];
        if (note == undefined) return;
        var noteNum = noteToNum[note];
        var freq = frequency(noteNum);
        var osc = createOscillator(freq);

        oscillators[e.keyCode] = osc;
        osc.start(0);
    };
    document.getElementById("pianito").onkeyup = function(e) {
        var osc = oscillators[e.keyCode];
        if (!osc) return;
        osc.stop(0);
        osc.disconnect(audio.destination);

        oscillators[e.keyCode] = undefined;
    };
})();


Bastante rudimentario, pero es algo para empezar


domingo, 6 de abril de 2014

Quadnet Project


Desde hace un par años tengo la intencion de meterme de lleno a Javascript, las razones de porque se analizan en este post: http://nilclass.blogspot.com.ar/2014/01/vuelta-el-blog.html

Considere que una buena manera de empezar, es con un proyecto "real", o sea que tenga como proposito desarrollar algo que sea utilizado (jugado) por un usuario final.

Podria crear algo nuevo o no, pero lo mas importante para mi es que el desafio sea tecnico: CSS, HTML, WebGL, Social Buttons, backend (o no), etc.... Por eso mismo decidi hacer un remake de un juego que me gustaba mucho, que se llamaba QUADNET

Quadnet


Mas o menos por el 1999, yo pasaba horas y horas jugando a este juego que es muy adictivo http://www.martinmagni.com/1998/12/quadnet-fast-and-furious-arcade-action, este juego lo desarrollo un Sueco (http://www.martinmagni.com) a partir de un concepto muy original, lo desarrollo para que corra en MS-DOS, aunque para ese año se estaba poniendo en voga los juegos que corren en windows, aun DOS era una buena alternativa como plataforma para la cual programar juegos. 

Es un juego original, sencillo, y al mismo tiempo muy bueno justamente por su sencillez. Es el proyecto perfecto como desafio introductorio al desarrollo de juegos en alguna plataforma.

El desarrollo


Como la mayoria de las cosas que hice las tuve que aprender, me plantie resolver solo un problema a la vez, en este orden:

  1. Como y donde hostear el juego: en una pagina de github
  2. Hacer objetos graficos del juego en una version rudimentaria (por ej: los asteriodes eran simples esferas)
  3. Desarrollar la logica basica del juego
  4. Completar el aspecto grafico de los objetos
  5. Efectos de explosiones similar al original
  6. Sonidos
  7. Musica :), tampoco me dedique a crear nada nuevo en este aspecto, pero si re-edite la musica del juego original de 1998
  8. Optimizar las explosiones, porque hasta en un  dual core se laggeaba :(
  9. Menu y pantallas de presentacion del juego, incluyendo instrucciones de como jugarlo
  10. Pantalla de "Leaderboard" que muestra los puntajes mas altos
  11. Botones de redes sociales
  12. Hacer que el Leaderboard sea online

Lecciones Aprendidas


Como ya mencione, el objetivo mas importantes que me plantie con este proyecto es aprender javascript "haciendo algo", y con este primer proyecto si que tuve que aprender varias cosas nuevas

Three.js


Por los visto, es LA libreria JS para hacer graficos 3D con WebGL en el browser, el API provisto por los browsers es apenas la minima necesaria para poder acceder a la funcionalidad (casi un calco de lo que es el API que se usaria en C) por lo que no tienen ninguna clase, patrones, funcionalidades accesorias, recursos (por ej shaders) que si agrega una libreria como three.js. Sin duda es preferible utilizar three.js a programar directamente sobre WebGL, al menos para empezar, y fue el caso con este proyecto.
Para mas informacion, vean los ejemplos de lo que esa libreria esa capaz de hacer de manera bastante sencilla: http://threejs.org/examples/

Promises


Promises es un patron muy util en javascript que se implemento como respuesta al tan temido callback hell, "callback hell" es lo que sucede cuando en javascript, se necesita realizar muchas operaciones asincronicas en secuencia (practicamente todo lo que puede demorar es asi en javascript) y aparentemente la mejor opcion si tenemos que hacer 1,2 y 3, llamemos a 2 en el callback de 1, a 3 en el callback de 2, y asi:

// hago tres request, una atras de otra
$.get('/url1/resource1', function(data1) {
  // hacer cosas con data1
  $.get('/url2/resource2', function(data2) {
    // hacer cosas con data1
    $.get('/url3/resource3', function(data3) {
      // hacer cosas con data3
    });
  });
  
});
Pero en lugar de eso...
$.get('/url1/resource1')
  .then(function(data1){
    // hacer cosas con data1
    return $.get('/url2/resource2');
  })
  .then(function(data2){
    // hacer cosas con data2
    return $.get('/url3/resource3');
  })
  .then(function(data3){
    // hacer cosas con data3
  });
Realmente hay que ejecutar esos request en secuencia?, si el resultado de uno no influye en como hacer los otros, se podria hacer asi para ejecutarlos en paralelo
$.when(
  $.get('/url1/resource1').done(function(data1){
    // hacer cosas con data1
  }),
  $.get('/url2/resource2').done(function(data2){
    // hacer cosas con data2
  }),
  $.get('/url3/resource3').done(function(data3){
    // hacer cosas con data3
  })
);
Pero, "necesito combinar data1, data2 y data3 para hacer algo con los tres". Entonces:
var data1, data2, data3;
$.when(
  $.get('/url1/resource1').done(function(result){
    data1 = result;
  }),
  $.get('/url1/resource2').done(function(result){
    data2 = result;
  }),
  $.get('/url1/resource3').done(function(result){
    data3 = result;
  })
).done(function() {
  // termino de ejecutar las tres peticiones
  // puedo hacer algo con data1, data2 y data3
});

En estos ejemplos utilize deferred, la implementacion de Promises que viene con jQuery, en mi proyecto utilize Promise que es otra alternativa, ambas son muy similares y el usar una u otra depende de la situacion (por ej, si ya estas usando jQuery tenes a mano deferred, pero talvez te interese Promise por el hecho de que implementa un API mas similar a la que aparentemente se estandarizara)


Memory Leaks


El entorno del browser (o node) donde corre javascript se encarga de gestionar la memoria mediante un Garbage Collector, tal como ocurre en Ruby, Python, Java, #NET y muchos otros, sin embargo esto no lo deja exento de problemas relacionados con Memory Leaks

En C o en C++ se debe utilizar la funcion free o la palabra reservada delete siempre para liberar la memoria que ocupa un objeto, en Javascript como ya se menciono esto ocurre automaticamente, pero el riesgo del memory leak ocurre cuando inadvertidamente se crean colecciones muy grandes de referencias a objetos, que nunca seran liberados de la memoria porq el garbage collector los considerada "reachables" 

En C y en C++ la pesadilla de los memory leaks si mitiga con herramientas como Valgrind que detecta elementos en el heap no liberados. 
En Javascript la primer herramienta que tuve a mano es el potente Heap Snapshot de Chrome, creo que el titulo lo dice todo: captura el estado actual del heap con todos sus objetos, y ademas muestra quien tiene referencia a quien, y la razon por la cual el GC no decidio borrarlo (que otros objetos o funciones-scope tienen referencais a el)




Por supuesto que al uso de esta herramienta se complementa las buenas practicas de la gestion de memoria dinamica, en el caso de C++ era asegurarse de borrar cosas en el destructor y usar la palabra new lo menos posible, o al menos encapsular toda esa gestion de memoria en una clase estructura (Arboles, listas, etc...)
En el caso de Javascript por el momento solo conozco una tres cosas (me faltaria averiguar si hay mas)
  • Setear a null las referencias que no se usaran mas, esto nos asegura que esas referencias no van a retener la liberacion de los objetos, no conviene usar delete porque acarrea problemas de performance
  • Evitar los closures innecesarios, ya que cuando se crean los closures estos matienen referencia a los scopes con sus variables y todos los objetos
  • Evitar tener arrays de objetos que crecen constantemente y sin ningun tipo de control


CSS Transitions and Transforms


No puedo creer lo sencillo que es setearlas, y las posibilidades que tiene, para dar un ejemplo, pasen el puntero por esta imagen:



Que paso?, la imagen tiene una class "escalando", entonces con este CSS:
img.escalando:hover {
  transform:scale(5,5);
  -ms-transform:scale(5,5); /* IE 9 */
  -webkit-transform:scale(5,5); /* Opera, Chrome, and Safari */
  transition: all 1s ease-out;
}
Se logra.

  1. Que cuando se pase el puntero por el elemento img, con class escalando, le aplique una transformacion de escalado a 5 veces su tamaño, y 
  2. Que utilice una transition que aplica a todos sus atributos de estilos (incluyendo al width y al height), esta transition en este caso dura un segundo (1s) y la hace con efecto de desaceleracion (ease-out)

Local Storage


Una nueva feature de HTML5, me sirvio para almacenar los highscores, la idea sencillamente es almacenar datos en la maquina donde se esta ejecutando la pagina, seria similar a lo que son las cookies, pero con la diferencia que no expiran y hay un espacio mas amplio (alrededor de 5MB por dominio en Chrome, en otros browsers anda mas o menos por lo mismo)

Se estructura como un hash clave-valor y su uso es tan sencillo como hacer esto:

window.localStorage.setItem("keyname", value)


Firebase (y el no-backend)


Mas tarde, muchos me dijeron o plantearon que seria interesante que la tabla de highscores no sea algo local a la maquina donde corre el juego, que sea algo centralizado para todas las instancias del juego, eso haria que el juego se convierte facilmente en algo competitivo, y casi "social".
De una imagine la solucion clasica: un aplicacion backend desarrollada posiblemente con Ruby con algun framework sencillo como sinatra, o desarrollada con Node.js, talvez hosteada en Heroku con su DB (algo simple, solo una tabla con los puntajes mas altos), y por supuesto el juego mandando los request a ese server

Pero alguien con una problematica similar en un proyecto muy groso para celulares, me recomendo que le de una mirada a Firebase. Que es Firebase?, a grandes rasgos una solucion "generica" de base de datos + backend, con la filosofia del "no-backend", que seria desarrollar apps distribuidas "sin backend" (bueno, en realidad usaria un servicio como Firebase, ellos cumplirian el rol de "backend") pero el punto es que con eso pude desarrollar el Leaderboard centralizado sin tener que preocuparme por hostear absolutamente nada ni programar algo server side, si quieren conocer mas detalles les recomendaria que se pasen por el sitio de Firebase: https://www.firebase.com/

Links


El juego hosteado en github: http://tario.github.io/quadnet/
Pagina del juego, con el codigo fuente: https://github.com/tario/quadnet
Sitio oficial de three.js: http://threejs.org/
Juego original al cual emula: http://www.martinmagnusson.com/games/quadnet/
Mas informacion de localStorage: http://www.w3schools.com/html/html5_webstorage.asp
Sitio oficial de Firebase: https://www.firebase.com/


sábado, 18 de enero de 2014

Vuelta el blog

Por diversas razones, talvez mas por dejadez que otra cosa he dejado gradualmente de bloggear hasta que en el 2012 para del todo, muchas cosas cambiaron desde la ultima vez que bloggie, cuando comente mis impresiones de la rubyconf 2012, y ya estamos en el 2014, y se hizo la rubyconf 2013 (a la que le dedicare un justo post)
Otra cosa que cambio, al menos en mi caso, la relevancia que le doy a la parte del desarrollo client-side, digamos que ya estamos bastante lejos de las epocas en que todo se hacia "en el server" y el browser actuaba como un simple renderizador de html. 
En la ultima decada, pero mas que nada en el ultimo par de años las cosas cambiaron mucho con respecto a lo que los browsers son capaces de hacer, de a poco se fueron agregando capacidades que antes solo se podian agregar a la aplicacion por medio de plugins, o directamente haciendo una app tradicional, por ej: WebRTC que permite desarrollar apps de comunicacion (como los softphones) 100% en Javascript, WebGL para aceleracion grafica y un largo etc...

Una muestra de lo que digo, es "Epic Citadel" para el caso de WebGL, y el hangout de google que utiliza lo de webrtc (creo)

Ruby sigue siendo un lenguaje potente y cada vez se extiende mas, pero el ecosistema y comunidad de ruby esta bastante orientado al desarrollo rapido de backend (casi ninguna tecnologia lo supera en eso), como excasas excepciones existen algunas gemas, algunas medio experimentales que ayudan para usar ruby client-side, solo enumero algunas:

  • Shoesrb: framework orientado a desarrollar interfaces de ventanas, para apps "tradicionales" (o sea, no web) con un azucar sintactico bastante sencillo, al estilo los frameworks webs mas conocidos como sinatra
  • Rubygame: Libreria multimedia que ayuda al desarrollo de juegos en ruby
  • OpalrbTranspiler que convierte codigo Ruby a Javascript para que pueda ser ejecutado en el browser

Y todas son excelentes, pero sufren el problema de ser complejos y aparatosos de instalar, no para el caso del desarrollador que esta canchero con eso, sino mas que nada para el usuario final, recuerden que al ser ruby un lenguaje interpretado, como minimo se debe instalar el interprete del lenguaje, y en el caso de usar librerias como shoesrb y rubygame, se tienen que instalar las dependencias, creo que gtk en el caso de shoes y sdl en el caso de rubygame

Opalrb como concepto se ve muy interesante, pero lamentablemente los browsers no dan soporte realmente bueno para debuggear lenguajes que no sean javascript, se que existe lo de source maps, pero lei por ahi que desarrollar con algo que no sea javascript para el browser sigue siendo complicado igual

En fin, llegue a la conclusion que Javascript es un lenguaje que hay que conocer si o si, al menos si tu intencion es hacer aplicaciones que sean sencillas de instalar y usar para el usuario final, por eso empece a hacer algunas pruebas, y con un tema que me gusta, los graficos 3D:

Para empezar una demo basica con figuras geometricas, muy elemental, pero si miran en el codigo fuente se puede ver hypercomentado, muy util para ir aprendiendo Javascript (como yo en el momento de escribir esas demos)
http://tario.github.io/threejs_demos/

Despues, un proyecto apuntando a algo, no esta terminado, mas tarde le dedicare un merecido post
http://tario.github.io/quadnet