SlideShare a Scribd company logo
1 of 94
Como el Desarrollo de
Videojuegos puede ayudarnos
a volvernos mejores
Desarrolladores Web




M. Andrés Pagella (@mapagella) - http://www.andrespagella.com
< 2003
< 2003
< 2003
< 2003
~2000
2004
2005
Mac OSX 10.4 Tiger

       2005
2007
2007
APUNTAR AL ‘MINIMO COMUN DENOMINADOR’ (?)
APUNTAR AL ‘MINIMO COMUN DENOMINADOR’ (?)
   Si anda bien en este, anda bien en todos.
PARA TENER EN CUENTA...
PARA TENER EN CUENTA...


Tiempo de Carga
PARA TENER EN CUENTA...


   Tiempo de Carga
Velocidad de Rendering
PARA TENER EN CUENTA...


   Tiempo de Carga
Velocidad de Rendering
Responsividad de la UI
Video Juegos
Video Juegos
OPTIMIZACIÓN DE TIEMPOS DE CARGA
OPTIMIZACIÓN DE TIEMPOS DE CARGA

Buen download bandwidth, pésima latencia
OPTIMIZACIÓN DE TIEMPOS DE CARGA

Buen download bandwidth, pésima latencia

Acomodar la mayor cantidad de información
      en el menor espacio posible
LAZY LOAD
Spritesheets / Atlas & Soundsheets (AKA Audio Sprites)
Spritesheets / Atlas & Soundsheets (AKA Audio Sprites)
Spritesheets / Atlas & Soundsheets (AKA Audio Sprites)
Spritesheets / Atlas & Soundsheets (AKA Audio Sprites)




                                        +
Spritesheets / Soundsheets (AKA Audio Sprites)



       Sound Manager 2 (Legacy support con fallbacks)
       http://www.schillmania.com/projects/soundmanager2/




       Zynga Jukebox (Optimizado para Mobile)
       https://github.com/zynga/jukebox
Heightmaps
Heightmaps
Heightmaps
Heightmaps
Heightmaps




       map.gif (150 bytes)
Heightmaps




       map.gif (150 bytes)
Heightmaps
Heightmaps




var Tile = {
! WALL: {
! ! index: 0,
! ! identifier: 'ffffff'
! },
! RED: {
! ! index: 1,
! ! identifier: '00ff'
! },
! BLUE: {
! ! index: 2,
! ! identifier: 'ff00'
! }
}
Heightmaps
                           Level.prototype.loadMap = function (map) {

                                // Create an HTML5 Canvas object, define the 2D Context and create an empty array to store the tileData
                                var c = this.c,
                                    cnv = document.createElement("canvas"),
                                    ctx = cnv.getContext("2d"),
                                    idata = null,
                                    tileData = [];

                                // Set the size of the map
                                this.mapData.size = {
                                    x: map.width,
                                    y: map.height
                                }
var Tile = {                    // Adjust the size of the canvas to match the size of the image
! WALL: {                       cnv.width = map.width;
                                cnv.height = map.height;
! ! index: 0,                   // Paint the map on the new canvas
! ! identifier: 'ffffff'        ctx.drawImage(map, 0, 0);

! },                            // Read the pixel data array
                                idata = ctx.getImageData(0, 0, cnv.width, cnv.height);
! RED: {                        // Start cycling through all the pixels of the image
! ! index: 1,                   for (var i = 0, my = map.height; i < my; ++i) {
                                    for (var j = 0, mx = map.width; j < mx; ++j) {
! ! identifier: '00ff'                  // Convert the RGB values to hex
                                        var r = (idata.data[((mx * i) + j) * 4]).toString(16),
! },                                        g = (idata.data[((mx * i) + j) * 4 + 1]).toString(16),
                                            b = (idata.data[((mx * i) + j) * 4 + 2]).toString(16),
! BLUE: {                                   hex = r + g + b;

! ! index: 2,                           tileData[j] = tileData[j] || [];

! ! identifier: 'ff00'                  switch(hex) {
                                            case Tile.WALL.identifier:
! }                                             tileData[j][i] = Tile.WALL.index;
                                                break;
}                                           case Tile.BLUE.identifier:
                                                tileData[j][i] = Tile.BLUE.index;
                                                this.mapData.base.blue = {x: j, y: i};
                                                break;
                                            case Tile.RED.identifier:
                                                tileData[j][i] = Tile.RED.index;
                                                this.mapData.base.red = {x: j, y: i};
                                                break;
                                        }
                                    }
                                }

                                // Replace the level data with the values of the tileData matrix.
                                this.mapData.data = tileData;
                           };
Otras consideraciones...
Otras consideraciones...

        Background Loading
Optimizaciones del lado del Servidor
    Optimizaciones de Imágenes
            Templates
                etc.
OPTIMIZACIÓN DE OPERACIONES DE PINTADO EN PANTALLA
OPTIMIZACIÓN DE OPERACIONES DE PINTADO EN PANTALLA


    Extremadamente “caras” en dispositivos móviles
OPTIMIZACIÓN DE OPERACIONES DE PINTADO EN PANTALLA


    Extremadamente “caras” en dispositivos móviles

           Consejo: Pensar “masivamente”
VIEWPORT
VIEWPORT
for (var i = 0; i < 3; ++i) {
               for (var j = 0; j < 3; ++j) {
VIEWPORT           pintarCelda();
               }
           }
VIEWPORT
for (var i = 0; i < 3; ++i) {
               for (var j = 0; j < 3; ++j) {
                   if (dentro_de_viewport()) {
VIEWPORT               pintarCelda();
                   }
               }
           }
VIEWPORT
1.000.000 Filas
VIEWPORT             x
           1.000.000 Columnas
var scroll = { x: 0, y: 0 },
!   tile = { width: 32, height: 32 },
!   tileMap = inicializarTileMap();

function pintar(c, canvas) {
!   c.fillStyle = '#FFFFFF';
!   c.fillRect (0, 0, canvas.width, canvas.height);
!   c.fillStyle = '#000000';

!   var   startRow   =   Math.floor(scroll.x / tile.width),
!   !     startCol   =   Math.floor(scroll.y / tile.height),
!   !     rowCount   =   startRow + Math.floor(canvas.width / tile.width) + 1,
!   !     colCount   =   startCol + Math.floor(canvas.height / tile.height) + 1;

!   for (var row = startRow; row < rowCount; ++row) {
!   !   for (var col = startCol; col < colCount; ++col) {
!   !   !    var tilePositionX = tile.width * row,
                 tilePositionY = tile.height * col;

!   !     !   tilePositionX -= scroll.x;
!   !     !   tilePositionY -= scroll.y;

!   !     !   if (dentro_de_viewport()) {
!   !     !   !   pintarCelda();
!   !     !   }
!   !     }
!   }
}
Dirty Rectangles / ATR (Adaptive Tile Refresh)
Dirty Rectangles / ATR (Adaptive Tile Refresh)
Layering, Compositing, etc...
Layering, Compositing, etc...




Static Layer
Layering, Compositing, etc...




Static Layer                   Animated Layer
Layering, Compositing, etc...
Layering, Compositing, etc...
Layering, Compositing, etc...
Layering, Compositing, etc...
Layering, Compositing, etc...
Layering, Compositing, etc...
Layering, Compositing, etc...
Layering, Compositing, etc...
Responsividad de la UI
Usar HTML/CSS para dibujar la GUI
Usar HTML/CSS para dibujar la GUI




Rovio/Google (Angry Birds GWT port), I’m looking at you...
Usar HTML/CSS para dibujar la GUI
Usar HTML/CSS para dibujar la GUI




ZeptoLabs/Microsoft (Cut the Rope), yay!
Usar HTML/CSS para dibujar la GUI
Usar HTML/CSS para dibujar la GUI




Autodesk Scaleform GFX (UDK) - Adobe Flash/AS2
Object Pooling
// Maximum number of sound objects allowed in the pool
var MAX_PLAYBACKS = 3;
var globalVolume = 0.3;

function SoundUtil()
{
!       this.maxPlaybacks = MAX_PLAYBACKS;
!       this.audioObjects = []; // Pool of audio objects available for reutilization
}

SoundUtil.prototype.play = function(file, startTime, duration, volume, loop)
{

!      // Get an audio object from pool
!      var audioObject = this.getAudioObject(),
!      !       suObj = this;

!      /**
!        * No audio objects are available on the pool. Don't play anything.
!        * NOTE: This is the approach taken by toy organs, alternatively you
!        * could also add objects into a queue to be played later on
!        */
!      if (audioObject !== null) {
!      !        audioObject.obj.loop = loop;
!      !        audioObject.obj.volume = volume;

!      !       for (var i = 0, l = file.length; i < l; ++i) {
!      !       !       if (audioObject.obj.canPlayType(file[i][1]) === "probably" ||
!      !       !       !       audioObject.obj.canPlayType(file[i][1]) === "maybe") {
!      !       !       !       audioObject.obj.src = file[i][0];
!      !       !       !       audioObject.obj.type = file[i][1];
!      !       !       !       break;
!      !       !       }
!      !       }

!      !       var playBack = function()
!      !       {
!      !       !       // Remove the event listener, otherwise it will keep getting called over and over agian
!      !       !       audioObject.obj.removeEventListener('canplaythrough', playBack, false);
!      !       !       audioObject.obj.currentTime = startTime;
!      !       !       audioObject.obj.play();

!      !       !       // There's no need to listen if the object has finished playing if it's playing in loop mode
!      !       !       if (!loop) {
!      !       !       !       setTimeout(function() {
!      !       !       !       !       audioObject.obj.pause();
!      !       !       !       !       suObj.freeAudioObject(audioObject);
!      !       !       !       }, duration);
!      !       !       }
!      !       }

!      !       audioObject.obj.addEventListener('canplaythrough', playBack, false);
!      }
}
Object Pooling
SoundUtil.prototype.getAudioObject = function()
{
!      if (this.audioObjects.length === 0) {
!      !      var a = new Audio();
!      !      var audioObject = {
!      !      !      id: 0,
!      !      !      obj: a,
!      !      !      busy: true
!      !      }

!     !      this.audioObjects.push (audioObject);

!     !      return audioObject;
!     } else {
!     !      for (var i = 0, l = this.audioObjects.length; i < l; ++i) {
!     !      !      if (!this.audioObjects[i].busy) {
!     !      !      !      this.audioObjects[i].busy = true;
!     !      !      !      return this.audioObjects[i];
!     !      !      }
!     !      }

!     !      // No audio objects are free. Can we create a new one?
!     !      if (this.audioObjects.length <= this.maxPlaybacks) {
!     !      !      var a = new Audio();
!     !      !      var audioObject = {
!     !      !      !      id: this.audioObjects.length,
!     !      !      !      obj: a,
!     !      !      !      busy: true
!     !      !      }

!     !      !      this.audioObjects.push (audioObject);

!     !      !      return audioObject;
!     !      } else {
!     !      !      return null;
!     !      }
!     }
}

SoundUtil.prototype.freeAudioObject = function(audioObject) {
!      for (var i = 0, l = this.audioObjects.length; i < l; ++i) {
!      !      if (this.audioObjects[i].id === audioObject.id) {
!      !      !      this.audioObjects[i].currentTime = 0;
!      !      !      this.audioObjects[i].busy = false;
!      !      }
!      }
}
Evitar instanciaciones en loops




// Pseudocódigo
while (activo()) {
! var obj = new Ejemplo(); // Ouch
! obj.configurar();
! obj.hacerAlgo();
}

    Casos de uso: Emisión de Partículas, Update loops
Mantener la lógica separada de la rutina de pintado


// Pseudocodigo
function actualizarVista()
{
! if (pasaAlgo()) {
! ! for (var i = 0, l = objetosEnLista.length; i < l; ++i) {
! ! ! hacerAlgo();
! ! }
! } else {
! ! for (var i = 0, l = elementos.length; i < l; ++i) {
! ! ! hacerOtraCosa();
! ! }
! }
!
! pintarEnPantalla();
}
Mantener la lógica separada de la rutina de pintado
// Pseudocodigo

function ejecutarLogica()
{
! if (pasaAlgo()) {
! ! for (var i = 0, l = objetosEnLista.length; i < l; ++i) {
! ! ! hacerAlgo();
! ! }
! } else {
! ! for (var i = 0, l = objetosEnLista.length; i < l; ++i) {
! ! ! hacerOtraCosa();
! ! }
! }
}

function actualizarVista()
{
! pintarEnPantalla();
}
Tablas de Valores




     Math.sqrt(<número>)
Math.pow(<número>, <potencia>)
Tablas de Valores
Tablas de Valores
Tablas de Valores




var raizCuadrada = arrayRaices[<numero>];
Ser conciente de la memoria utilizada por un objeto




grilla[114422, 1233] = new ObjetoEjemplo();
Ser conciente de la memoria utilizada por un objeto




  grilla[114422, 1233] = new ObjetoEjemplo();




https://github.com/andrespagella/Making-Isometric-Real-time-Games/
                    blob/master/examples/astar.js
"Es divertido hacer lo imposible."
           Walt Disney
¡Gracias!

@mapagella - https://github.com/andrespagella/ - http://www.andrespagella.com

More Related Content

More from Andres Pagella

Desarrollo de videojuegos con HTML5, CSS3 y JavaScript en el Mundo Real
Desarrollo de videojuegos con HTML5, CSS3 y JavaScript en el Mundo RealDesarrollo de videojuegos con HTML5, CSS3 y JavaScript en el Mundo Real
Desarrollo de videojuegos con HTML5, CSS3 y JavaScript en el Mundo RealAndres Pagella
 
Resolviendo Problemas Imposibles
Resolviendo Problemas ImposiblesResolviendo Problemas Imposibles
Resolviendo Problemas ImposiblesAndres Pagella
 
Applying Old Videogame Performance Techniques to Modern Web-Based Games
Applying Old Videogame Performance Techniques to Modern Web-Based GamesApplying Old Videogame Performance Techniques to Modern Web-Based Games
Applying Old Videogame Performance Techniques to Modern Web-Based GamesAndres Pagella
 
Barcamp 2010 - Un vistazo al futuro de la web
Barcamp 2010 - Un vistazo al futuro de la webBarcamp 2010 - Un vistazo al futuro de la web
Barcamp 2010 - Un vistazo al futuro de la webAndres Pagella
 

More from Andres Pagella (6)

Desarrollo de videojuegos con HTML5, CSS3 y JavaScript en el Mundo Real
Desarrollo de videojuegos con HTML5, CSS3 y JavaScript en el Mundo RealDesarrollo de videojuegos con HTML5, CSS3 y JavaScript en el Mundo Real
Desarrollo de videojuegos con HTML5, CSS3 y JavaScript en el Mundo Real
 
Resolviendo Problemas Imposibles
Resolviendo Problemas ImposiblesResolviendo Problemas Imposibles
Resolviendo Problemas Imposibles
 
Memmangementjs
MemmangementjsMemmangementjs
Memmangementjs
 
onGameStart
onGameStartonGameStart
onGameStart
 
Applying Old Videogame Performance Techniques to Modern Web-Based Games
Applying Old Videogame Performance Techniques to Modern Web-Based GamesApplying Old Videogame Performance Techniques to Modern Web-Based Games
Applying Old Videogame Performance Techniques to Modern Web-Based Games
 
Barcamp 2010 - Un vistazo al futuro de la web
Barcamp 2010 - Un vistazo al futuro de la webBarcamp 2010 - Un vistazo al futuro de la web
Barcamp 2010 - Un vistazo al futuro de la web
 

JSConf Argentina 2012 - Como el Desarrollo de Videojuegos puede ayudarnos a volvernos mejores Desarrolladores Web por Andres Pagella

  • 1. Como el Desarrollo de Videojuegos puede ayudarnos a volvernos mejores Desarrolladores Web M. Andrés Pagella (@mapagella) - http://www.andrespagella.com
  • 2.
  • 10. Mac OSX 10.4 Tiger 2005
  • 11. 2007
  • 12. 2007
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19. APUNTAR AL ‘MINIMO COMUN DENOMINADOR’ (?)
  • 20. APUNTAR AL ‘MINIMO COMUN DENOMINADOR’ (?) Si anda bien en este, anda bien en todos.
  • 21. PARA TENER EN CUENTA...
  • 22. PARA TENER EN CUENTA... Tiempo de Carga
  • 23. PARA TENER EN CUENTA... Tiempo de Carga Velocidad de Rendering
  • 24. PARA TENER EN CUENTA... Tiempo de Carga Velocidad de Rendering Responsividad de la UI
  • 28. OPTIMIZACIÓN DE TIEMPOS DE CARGA Buen download bandwidth, pésima latencia
  • 29. OPTIMIZACIÓN DE TIEMPOS DE CARGA Buen download bandwidth, pésima latencia Acomodar la mayor cantidad de información en el menor espacio posible
  • 31. Spritesheets / Atlas & Soundsheets (AKA Audio Sprites)
  • 32. Spritesheets / Atlas & Soundsheets (AKA Audio Sprites)
  • 33. Spritesheets / Atlas & Soundsheets (AKA Audio Sprites)
  • 34. Spritesheets / Atlas & Soundsheets (AKA Audio Sprites) +
  • 35. Spritesheets / Soundsheets (AKA Audio Sprites) Sound Manager 2 (Legacy support con fallbacks) http://www.schillmania.com/projects/soundmanager2/ Zynga Jukebox (Optimizado para Mobile) https://github.com/zynga/jukebox
  • 40. Heightmaps map.gif (150 bytes)
  • 41. Heightmaps map.gif (150 bytes)
  • 43. Heightmaps var Tile = { ! WALL: { ! ! index: 0, ! ! identifier: 'ffffff' ! }, ! RED: { ! ! index: 1, ! ! identifier: '00ff' ! }, ! BLUE: { ! ! index: 2, ! ! identifier: 'ff00' ! } }
  • 44. Heightmaps Level.prototype.loadMap = function (map) { // Create an HTML5 Canvas object, define the 2D Context and create an empty array to store the tileData var c = this.c, cnv = document.createElement("canvas"), ctx = cnv.getContext("2d"), idata = null, tileData = []; // Set the size of the map this.mapData.size = { x: map.width, y: map.height } var Tile = { // Adjust the size of the canvas to match the size of the image ! WALL: { cnv.width = map.width; cnv.height = map.height; ! ! index: 0, // Paint the map on the new canvas ! ! identifier: 'ffffff' ctx.drawImage(map, 0, 0); ! }, // Read the pixel data array idata = ctx.getImageData(0, 0, cnv.width, cnv.height); ! RED: { // Start cycling through all the pixels of the image ! ! index: 1, for (var i = 0, my = map.height; i < my; ++i) { for (var j = 0, mx = map.width; j < mx; ++j) { ! ! identifier: '00ff' // Convert the RGB values to hex var r = (idata.data[((mx * i) + j) * 4]).toString(16), ! }, g = (idata.data[((mx * i) + j) * 4 + 1]).toString(16), b = (idata.data[((mx * i) + j) * 4 + 2]).toString(16), ! BLUE: { hex = r + g + b; ! ! index: 2, tileData[j] = tileData[j] || []; ! ! identifier: 'ff00' switch(hex) { case Tile.WALL.identifier: ! } tileData[j][i] = Tile.WALL.index; break; } case Tile.BLUE.identifier: tileData[j][i] = Tile.BLUE.index; this.mapData.base.blue = {x: j, y: i}; break; case Tile.RED.identifier: tileData[j][i] = Tile.RED.index; this.mapData.base.red = {x: j, y: i}; break; } } } // Replace the level data with the values of the tileData matrix. this.mapData.data = tileData; };
  • 46. Otras consideraciones... Background Loading Optimizaciones del lado del Servidor Optimizaciones de Imágenes Templates etc.
  • 47. OPTIMIZACIÓN DE OPERACIONES DE PINTADO EN PANTALLA
  • 48. OPTIMIZACIÓN DE OPERACIONES DE PINTADO EN PANTALLA Extremadamente “caras” en dispositivos móviles
  • 49. OPTIMIZACIÓN DE OPERACIONES DE PINTADO EN PANTALLA Extremadamente “caras” en dispositivos móviles Consejo: Pensar “masivamente”
  • 50.
  • 53. for (var i = 0; i < 3; ++i) { for (var j = 0; j < 3; ++j) { VIEWPORT pintarCelda(); } }
  • 55. for (var i = 0; i < 3; ++i) { for (var j = 0; j < 3; ++j) { if (dentro_de_viewport()) { VIEWPORT pintarCelda(); } } }
  • 57. 1.000.000 Filas VIEWPORT x 1.000.000 Columnas
  • 58. var scroll = { x: 0, y: 0 }, ! tile = { width: 32, height: 32 }, ! tileMap = inicializarTileMap(); function pintar(c, canvas) { ! c.fillStyle = '#FFFFFF'; ! c.fillRect (0, 0, canvas.width, canvas.height); ! c.fillStyle = '#000000'; ! var startRow = Math.floor(scroll.x / tile.width), ! ! startCol = Math.floor(scroll.y / tile.height), ! ! rowCount = startRow + Math.floor(canvas.width / tile.width) + 1, ! ! colCount = startCol + Math.floor(canvas.height / tile.height) + 1; ! for (var row = startRow; row < rowCount; ++row) { ! ! for (var col = startCol; col < colCount; ++col) { ! ! ! var tilePositionX = tile.width * row, tilePositionY = tile.height * col; ! ! ! tilePositionX -= scroll.x; ! ! ! tilePositionY -= scroll.y; ! ! ! if (dentro_de_viewport()) { ! ! ! ! pintarCelda(); ! ! ! } ! ! } ! } }
  • 59.
  • 60.
  • 61.
  • 62. Dirty Rectangles / ATR (Adaptive Tile Refresh)
  • 63. Dirty Rectangles / ATR (Adaptive Tile Refresh)
  • 66. Layering, Compositing, etc... Static Layer Animated Layer
  • 76. Usar HTML/CSS para dibujar la GUI
  • 77. Usar HTML/CSS para dibujar la GUI Rovio/Google (Angry Birds GWT port), I’m looking at you...
  • 78. Usar HTML/CSS para dibujar la GUI
  • 79. Usar HTML/CSS para dibujar la GUI ZeptoLabs/Microsoft (Cut the Rope), yay!
  • 80. Usar HTML/CSS para dibujar la GUI
  • 81. Usar HTML/CSS para dibujar la GUI Autodesk Scaleform GFX (UDK) - Adobe Flash/AS2
  • 82. Object Pooling // Maximum number of sound objects allowed in the pool var MAX_PLAYBACKS = 3; var globalVolume = 0.3; function SoundUtil() { ! this.maxPlaybacks = MAX_PLAYBACKS; ! this.audioObjects = []; // Pool of audio objects available for reutilization } SoundUtil.prototype.play = function(file, startTime, duration, volume, loop) { ! // Get an audio object from pool ! var audioObject = this.getAudioObject(), ! ! suObj = this; ! /** ! * No audio objects are available on the pool. Don't play anything. ! * NOTE: This is the approach taken by toy organs, alternatively you ! * could also add objects into a queue to be played later on ! */ ! if (audioObject !== null) { ! ! audioObject.obj.loop = loop; ! ! audioObject.obj.volume = volume; ! ! for (var i = 0, l = file.length; i < l; ++i) { ! ! ! if (audioObject.obj.canPlayType(file[i][1]) === "probably" || ! ! ! ! audioObject.obj.canPlayType(file[i][1]) === "maybe") { ! ! ! ! audioObject.obj.src = file[i][0]; ! ! ! ! audioObject.obj.type = file[i][1]; ! ! ! ! break; ! ! ! } ! ! } ! ! var playBack = function() ! ! { ! ! ! // Remove the event listener, otherwise it will keep getting called over and over agian ! ! ! audioObject.obj.removeEventListener('canplaythrough', playBack, false); ! ! ! audioObject.obj.currentTime = startTime; ! ! ! audioObject.obj.play(); ! ! ! // There's no need to listen if the object has finished playing if it's playing in loop mode ! ! ! if (!loop) { ! ! ! ! setTimeout(function() { ! ! ! ! ! audioObject.obj.pause(); ! ! ! ! ! suObj.freeAudioObject(audioObject); ! ! ! ! }, duration); ! ! ! } ! ! } ! ! audioObject.obj.addEventListener('canplaythrough', playBack, false); ! } }
  • 83. Object Pooling SoundUtil.prototype.getAudioObject = function() { ! if (this.audioObjects.length === 0) { ! ! var a = new Audio(); ! ! var audioObject = { ! ! ! id: 0, ! ! ! obj: a, ! ! ! busy: true ! ! } ! ! this.audioObjects.push (audioObject); ! ! return audioObject; ! } else { ! ! for (var i = 0, l = this.audioObjects.length; i < l; ++i) { ! ! ! if (!this.audioObjects[i].busy) { ! ! ! ! this.audioObjects[i].busy = true; ! ! ! ! return this.audioObjects[i]; ! ! ! } ! ! } ! ! // No audio objects are free. Can we create a new one? ! ! if (this.audioObjects.length <= this.maxPlaybacks) { ! ! ! var a = new Audio(); ! ! ! var audioObject = { ! ! ! ! id: this.audioObjects.length, ! ! ! ! obj: a, ! ! ! ! busy: true ! ! ! } ! ! ! this.audioObjects.push (audioObject); ! ! ! return audioObject; ! ! } else { ! ! ! return null; ! ! } ! } } SoundUtil.prototype.freeAudioObject = function(audioObject) { ! for (var i = 0, l = this.audioObjects.length; i < l; ++i) { ! ! if (this.audioObjects[i].id === audioObject.id) { ! ! ! this.audioObjects[i].currentTime = 0; ! ! ! this.audioObjects[i].busy = false; ! ! } ! } }
  • 84. Evitar instanciaciones en loops // Pseudocódigo while (activo()) { ! var obj = new Ejemplo(); // Ouch ! obj.configurar(); ! obj.hacerAlgo(); } Casos de uso: Emisión de Partículas, Update loops
  • 85. Mantener la lógica separada de la rutina de pintado // Pseudocodigo function actualizarVista() { ! if (pasaAlgo()) { ! ! for (var i = 0, l = objetosEnLista.length; i < l; ++i) { ! ! ! hacerAlgo(); ! ! } ! } else { ! ! for (var i = 0, l = elementos.length; i < l; ++i) { ! ! ! hacerOtraCosa(); ! ! } ! } ! ! pintarEnPantalla(); }
  • 86. Mantener la lógica separada de la rutina de pintado // Pseudocodigo function ejecutarLogica() { ! if (pasaAlgo()) { ! ! for (var i = 0, l = objetosEnLista.length; i < l; ++i) { ! ! ! hacerAlgo(); ! ! } ! } else { ! ! for (var i = 0, l = objetosEnLista.length; i < l; ++i) { ! ! ! hacerOtraCosa(); ! ! } ! } } function actualizarVista() { ! pintarEnPantalla(); }
  • 87. Tablas de Valores Math.sqrt(<número>) Math.pow(<número>, <potencia>)
  • 90. Tablas de Valores var raizCuadrada = arrayRaices[<numero>];
  • 91. Ser conciente de la memoria utilizada por un objeto grilla[114422, 1233] = new ObjetoEjemplo();
  • 92. Ser conciente de la memoria utilizada por un objeto grilla[114422, 1233] = new ObjetoEjemplo(); https://github.com/andrespagella/Making-Isometric-Real-time-Games/ blob/master/examples/astar.js
  • 93. "Es divertido hacer lo imposible." Walt Disney

Editor's Notes

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n
  54. \n
  55. \n
  56. \n
  57. \n
  58. \n
  59. \n
  60. \n
  61. \n
  62. \n
  63. \n
  64. \n
  65. \n
  66. \n
  67. \n
  68. \n
  69. \n
  70. \n
  71. \n
  72. \n
  73. \n
  74. \n
  75. \n
  76. \n
  77. \n
  78. \n
  79. \n
  80. \n
  81. \n
  82. \n
  83. \n
  84. \n
  85. \n
  86. \n
  87. \n
  88. \n
  89. \n
  90. \n
  91. \n
  92. \n
  93. \n
  94. \n
  95. \n
  96. \n
  97. \n