Fecha actual Dom Ago 18, 2019 9:59 am

[Udacity]CS255: Desarrollo de un Juego en HTML5

Aquí no solo haremos referencia a recursos de cursos interactivos en línea, etc., sino que también los desarrollaremos, en principio usando nuestra Técnica de Ejecución de Instrucciones Humanas, entre muchas otras, conocidas y nuevas desarrolladas durante nuestro estudio.


Usuarios leyendo este tema: Ninguno

[Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mar Feb 05, 2013 5:50 pm

Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mar Feb 05, 2013 6:06 pm

Link a la Clase/Sitio Oficial

(Este curso depende de la clase CS253: Ingeniería de Aplicaciones Web)


Esta clase está orientada simplemente a enseñar las bases de la creación de un juego, usando HTML5, Canvas y otros elementos.

Desde el principio es notorio el uso de JavaScript orientado a objetos y JSON.

Sé que esas cosas son usadas únicamente por gente que se dedica de lleno a crear interfaces web, y por eso esta discusión sobre esos temas va a ser útil para muchos de nosotros, seguramente más de la mitad (JSON y JavaScript orientado a objetos después de todo no suenan mucho en nuestro entorno inmediato, y significa que son cosas que la mayoría de desarrolladores no suele usar o dominar).

Ni siquiera yo, que he estado usando Low Leval JavaScript, he tenido la necesidad de usar JSON (porque hasta ahora he transferido solo datos de archivo 100% binarios para interpretar su formato manualmente), y tampoco he usado JavaScript orientado a objetos, para que sea similar a clases de Java, con métodos y propiedades.

Esto último es más elección de gusto. Hasta ahora, debido a que me interesa principalmente dominar C y Ensamblador, y de ahí dominar un poco de C++, mi estilo de programación es el típico basado en procedimientos (es más simple de portear y de usar en entornos de bajo nivel).

Lo más que puedo hacer ahora en JavaScript que se asemeja a orientación a objetos es algo como esto:

Código: Seleccionar todo
var objetoEmpacado=new Object();

objetoEmpacado.metodo1=function(){alert("Función 1.");};

objetoEmpacado.propiedad1="Variable 1.";


Usar esto es más cuestión de costumbre y gustos, pero podríamos usar la "notación literal" (la pregunta es, ¿por qué exactamente se le llama notación literal?).



También vamos a necesitar los links oficiales de la especificación de JSON:
http://www.json.org/
http://www.json.org/js.html
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mar Feb 05, 2013 6:14 pm

Lo primero a explorar es cómo usar JSON.

Se dice que JSON usa la sintaxis de declaración literal de objetos, y en la clase se hace la comparación que usar JSON es más fácil y liviano que usar XML (de hecho, es fácil convertir entre uno y otro).

La diferencia es que al declarar un objeto, los nombres de sus propiedades y métodos no están entre comillas, pero en JSON estos deben estar entre comillas.

Comenzamos con un objeto JSON vacío, para distinguir cómo se usa:

Código: Seleccionar todo
    var objetoJSON = {
   
    };




El siguiente paso es agregar, dentro de los corchetes de objetoJSON, el siguente código:

Código: Seleccionar todo
         "propiedad1":{
                       "a":5
         }



Eso agrega la propiedad llamada "propiedad1", y su subpropiedad, llamada "a".

Podemos tener tantos corchetes anidados como necesitemos.


Ahora necesitamos distinguir entre un objeto normal y un objeto JSON.

El siguiente es un objeto normal:
Código: Seleccionar todo
var objetoJSON = {
         propiedad1:{
                       a:5
         }
    };




Y este otro es un objeto JSON:
Código: Seleccionar todo
var objetoJSON = {
         "propiedad1":{
                       "a":5
         }
    };



A cualquiera de estos podemos accederlos usando objetoJSON.propiedad1.a, pero no se considera JSON válido a menos que todos los nombres de propiedades estén entre comillas ("propiedad1" y "a", junto con comillas).
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mar Feb 05, 2013 6:41 pm

Ahora, en el primer ejercicio, nos piden que usemos JSON.parse para finalmente obtener el valor de x, devolverlo e imprimirlo a la consola.

Lo que necesitamos es saber:

- Cómo llamar a JSON.parse

- Qué devuelve, y con qué propósito, para continuar.
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mar Feb 05, 2013 7:13 pm

Esto implica lo siguiente:

- Como nos dijeron, debemos usar la variable JSON para llamar la función parseJSON (una simple función de una única línea, que nosotros escribiremos). Dicha variable JSON es texto JSON basado en un objeto JSON, no el objeto en sí.

Si tenemos un objeto JSON, podemos convertirlo a una cadena JSON usando la rutina nativa JSON.stringify:
Código: Seleccionar todo
var cadenaJSON=JSON.stringify(objetoJSON);




Si tenemos una cadena JSON, podemos convertirla a un objeto JSON usando la rutina nativa JSON.parse:
Código: Seleccionar todo
var objetoJSON=JSON.parse(cadenaJSON);





Entonces, para el siguiente ejemplo de JSON, lo convertiremos a una cadena para demostrar el uso de las dos funciones anteriores:
Código: Seleccionar todo
JSONExample = {
    "frames": {
        "chaingun.png": {
            "frame": {
                "x": 1766,
                "y": 202,
                "w": 42,
                "h": 34
            },
            "rotated": false,
            "trimmed": true,
            "spriteSourceSize": {
                "x": 38,
                "y": 32,
                "w": 42,
                "h": 34
            },
            "sourceSize": {
                "w": 128,
                "h": 128
            }
        },
        "chaingun_impact.png": {
            "frame": {
                "x":1162,
                "y":322,
                "w":38,
                "h":34},
            "rotated": false,
            "trimmed": true,
            "spriteSourceSize": {
                "x":110,
                "y":111,
                "w":38,
                "h":34},
            "sourceSize": {
                "w":256,
                "h":256}
        },
        "chaingun_impact_0000.png": {
            "frame": {
                "x": 494,
                "y": 260,
                "w": 22,
                "h": 22
            },
            "rotated": false,
            "trimmed": true,
            "spriteSourceSize": {
                "x": 113,
                "y": 108,
                "w": 22,
                "h": 22
            },
            "sourceSize": {
                "w": 256,
                "h": 256
            }
        }
    }
};



Convertimos el objeto JSON a cadena JSON:
Código: Seleccionar todo
var cadenaJSON=JSON.stringify(JSONExample);




Ahora convertimos la cadena JSON a objeto JSON, y accedemos una propiedad anidada en varios niveles de anidación:
Código: Seleccionar todo
JSON.parse(cadenaJSON).frames["chaingun_impact.png"].spriteSourceSize.x;



Podemos hacer lo mismo exactamente de la siguiente forma:
Código: Seleccionar todo
JSON.parse(cadenaJSON)["frames"]["chaingun_impact.png"]["spriteSourceSize"]["x"];



Lo que sí es de notar desde este momento es que los nombres de las propiedades pueden tener un punto . que normalmente es un carácter especial, pero podemos accederlo usando notación de corchetes y comillas como en un arreglo, como mostramos justo antes de este párrafo.
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mar Feb 05, 2013 8:25 pm

El segundo ejercicio es sobre XMLHttpRequest.

Esto es algo bastante simple y, ya que estamos usando características presentes solo en las versiones más modernas de los navegadores, tales como HTML5 y JSON, no tiene sentido soportar XMLHttpRequest para navegadores antiguos, como Internet Explorer usando la versión ActiveX de XMLHttpRequest.

Así que esto es fácil. Primero, necesitamos crear un objeto XMLHttpRequest:
Código: Seleccionar todo
var objetoXHR = new XMLHttpRequest();



Después necesitamos abrir una conexión. Aquí especificamos el métido "GET", una URL simple, y un valor de true, que significa que la petición será asíncrona.
Código: Seleccionar todo
objetoXHR.open(
               "GET",
               "/media/js/standalone/libs/gamedev_assets/weapon.json",
               true
              );



En otras palabras eso significa que esta creará un nuevo hilo de ejecución que correrá en paralelo con el resto de hilos del navegador; gracias a eso, podemos esperar de forma transparente a recuperar todos los datos, en lugar de hacer que el navegador entero se atasque hasta que obtengamos el 100% de los datos pedidos (este es el efecto de una petición síncrona).

____________________________________________
Lo siguiente que necesitamos es establecer una rutina para el evento onload del objeto XMLHttpRequest. Esta es una complicación necesaria para una petición asíncrona: Ya que no sabemos cuándo regresará, simplemente establecemos esta rutina para que se gatille justo cuando los datos estén listos.

Para una petición asíncrona podríamos simplemente recuperar la propiedad objetoXHR.responseText inmediatamente después de que el navegador se atasque (pero esto es demasiado ineficiente y destruye la experiencia del usuario).

Así que, para establecer la rutina de onload, hacemos lo siguiente:
Código: Seleccionar todo
objetoXHR.onload = function(oEvent)
{
  //Procesar cuando la petición esté completamente cargada:
  ///
   if(this.readyState==4)
   {
    //Guardar el contenido del documento web:
    ///
     variableTextoGlobal=this.responseText;
   }
};




Finalmente, enviamos realmente la petición (anteriormente solo creamos el objeto XMLHttpRequest, abrimos una conexión asíncrona, y establecimos su evento onload). Esto lo hacemos con la siguiente línea:
Código: Seleccionar todo
objetoXHR.send();




Ahora, en nuestro programa necesitaríamos esperar una cantidad indeterminada, desconocida, de tiempo, para recuperar el contenido válido de variableTextoGlobal.

Esta es una consecuencia de la programación asíncrona. Esto lo podemos manejar estableciendo variableTextoGlobal inicialmente a null (para indicar que no se ha recuperado nada válido aún).

Después, necesitaríamos como mínimo un nuevo hilo de ejecución, creado con setInterval, que se gatille por ejemplo cada 50 o 100 milisegundos llamando la función de este hilo encargada de determinar si variableTextoGlobal ya no es null y en ese caso, llevar a cabo otras funciones, despertar/crear otro hilo de ejecución y desactivarse a sí mismo dado que su trabajo ya terminó.

El problema es que no podemos simplemente devolver de forma breve un valor desde la función objetoXHR.responseText hacia otra variable, global o local, porque no habrá nadie esperando a recuperar dicha variable después de un tiempo indeterminado; así que tenemos que usar otros métodos más creativos para guardar esta variable.

Un bucle común para comprobar que los datos están cargados, sipmle y sencillamente no serviría porque terminaría bloqueando el navegador después de unos segundos y unas miles de iteraciones sin control de intervalo.

Seguramente la clase va a tener todos estos elementos más adelante, aunque en lugar de setInterval, es posible que usemos "Worker Threads" (tal vez). Si es así, habrá que volverse versado en su uso.
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mar Feb 05, 2013 9:41 pm

Ya es el tercer problema de la lección de JavaScript, y ya están usando cosas que me tomó varios meses en decidirme a dominar.

Por ejemplo están usando Typed Arrays (parte de Low Level JavaScript) con XMLHttpRequest. Esto es confuso en un principio pero aquí lo explico de forma breve.

Esto sirve para obtener datos binarios puros para leerlos como valores de 8, 16 o 32 bits con o sin signo, o valores flotantes, y para las APIs de HTML5. Usar datos binarios puros le dan a nuestro código de JavaScript y a las APIs nativas mucha eficiencia.

Creamos el objeto XMLHttpRequest:
Código: Seleccionar todo
var objetoXHR = new XMLHttpRequest();




Establecemos propiedades. Aquí es vital establecer objetoXHR.responseType a "arraybuffer" para que los datos obtenidos sean 100% binarios:
Código: Seleccionar todo
objetoXHR.open("GET", "/media/js/standalone/libs/gamedev_assets/bg_menu.ogg", true);
objetoXHR.responseType = "arraybuffer";  //Establecer el tipo a ArrayBuffer
objetoXHR.timeout=0;  //Timeout en milisegundos (0 para desactivar)




Establecemos la función objetoXHR.onload. Aquí es vital obtener la propiedad objetoXHR.response, en lugar del usual objetoXHR.responseText, para que obtengamos los datos 100% binarios de bajo nivel (esto es vital para usar la API de sonido de HTML5, la que necesito investigar):
Código: Seleccionar todo
objetoXHR.onload = function(oEvent)
{
  //Procesar cuando la petición esté completamente cargada:
  ///
   if(this.readyState==4)
   {
    //Guardar el contenido del documento web.
    //Para ArrayBuffer, debemos usar this.response
    //en lugar de this.responseText:
    ///
     variableTextoGlobal=this.response;
   }
};




Finalmente enviamos nuevamente la petición de hecho:
Código: Seleccionar todo
objetoXHR.send();
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mar Feb 05, 2013 9:50 pm

El cuarto ejercicio nos pide crear una función de utilería para llamar fácilmente a XMLHttpRequest.

Si algo he aprendido durante la creación de la API de GIFs para JavaScript, es que crear tal función de utilería es truculento pero posible (necesita una función de callback que le pasamos como "puntero"), y conveniente porque de lo contrario sería mucho código repetido o de baja calidad.

Me baso en mi función de demostración del programa de API de GIFs, y voy a rescatar solo la parte del parámetro de URL, la función externa (externFn) y llamar dicha función con el documento web binario que leímos, no usando un hilo extra sino que en el momento preciso en el que la carga está completa (una forma altarna a usar hileras y, como lo demuestra la coincidencia entre mi función y los requerimientos del curso, bastante eficiente):
Código: Seleccionar todo
//Function to read an image from HTTP using
//XMLHttpRequest:
///
 function GETReadHTTPFile_Threading(_f_, timeout, responseObjs, idx, externFn, triggerExternFn)
 {
  //Create the request object (oReq)
  //and set its returned data type:
  ///
   var oReq = new XMLHttpRequest();    //Create object
   oReq.timeout=timeout;               //Set the timeout
   oReq.open("GET", _f_, true);        //Create a threading/non-blocking connection
   oReq.responseType = "arraybuffer";  //Set the type to ArrayBuffer



  //Create the onload function for the XMLHttpRequest object:
  ///
   oReq.onload = function (oEvent)
   {
     if(this.readyState==4)
     {
      responseObjs[idx]=new Array(this.readyState, this.status, this.response, this.getAllResponseHeaders());

      //If we have been told to run the external function,
      //which will handle the response contents, do so:
      ///
       if(typeof(externFn)=="function" && triggerExternFn)
        externFn(this.readyState, this.status, this.response, this.getAllResponseHeaders());

      return;
     }
   };


  //After setting up the properties of the XMLHttpRequest
  //and setting its onload event, we will send the request:
  ///
   oReq.send(null);


  //If we are here, it just means that everything was
  //set up OK properly:
  ///
   return oReq;
 }





La función reescrita para el curso sería:
Código: Seleccionar todo
function xhrGet(reqUri, callback, type) {
    // YOUR CODE HERE
   var oReq = new XMLHttpRequest();
   oReq.open("GET", reqUri, true);
   oReq.responseType = type;
   oReq.timeout=0;

   oReq.onload = function (oEvent)
   {
     if(this.readyState==4)
     {
       if(typeof(callback)=="function")
        callback(this);

      return;
     }
   };


   oReq.send(null);
}




Con estos ya son varios trucos usados que me tardaron buen tiempo en depurar totalmente.
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mar Feb 05, 2013 10:57 pm

El quinto ejercicio nos pide manejar el DOM (Document Object Model) para para agregar un DIV y, dentro de este un HTML5 Canvas.

Podríamos agregar primero el DIV con body.appendChild y después el Canvas con divID.appendChild, pero es mejor hacer esto en una única operación, primero creando el DIV (sin agregarlo al HTML) y después crear el Canvas agregándolo al DIV; y solo al final agregar el DIV con body.appendChild.


La forma estándar de lograr esto sin las particularidades del curso es:
Código: Seleccionar todo
 var body=document.getElementsByTagName("body")[0];
    var gameContent=document.createElement("div");
        gameContent.id="gameContent";
        gameContent.style.backgroundColor="#000000";
//        body.appendChild(gameContent);

    var gameCanvas=document.createElement("canvas");
        gameCanvas.id="gameCanvas";
        gameCanvas.style.backgroundColor="#abcdef";
        gameCanvas.width=16;
        gameCanvas.height=16;
        gameContent.appendChild(gameCanvas);

  body.appendChild(gameContent);



Aquí hay varias propiedades de muestra, y las especialmente interesantes son las del Canvas.

Desde este momento me parece bien mencionar un detalle poco obvio que volvía la renderización de mis programas confusa: Si cambiamos las propiedades objetoCanvas.width u objetoCanvas.height, perderemos cualquier cosa que hayamos escrito en el Canvas, y este se revertirá a su color de fondo original, cualquiera que este sea.
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mar Feb 05, 2013 11:26 pm

El sexto problema aparentemente no es tan complicado, pero lo interesante parece estar totalmente fuera de lo mostrado en este script, ya resuelto:
Código: Seleccionar todo

// Create an inheritance tree using Class.extend() of the
// following form:
//
// 1) Weapon should extend Class.
//
// 2) MachineGun should extend Weapon.
//
// 3) ChainGun should extend Weapon.
//
// 4) Entity should extend Class.
//
// 5) Teleporter should extend Entity.
//
// 6) EnergyCanister should extend Entity.
//
// We've started things off for you by doing steps
// (1) and (2).

Weapon = Class.extend({
    init: function() {
       
    }
});

MachineGun = Weapon.extend({
    init: function() {
       
    }
});

// YOUR CODE HERE


ChainGun = Weapon.extend({
    init: function() {
       
    }
});


Entity = Class.extend({
    init: function() {
       
    }
});


Teleporter = Entity.extend({
    init: function() {
       
    }
});




EnergyCanister = Entity.extend({
    init: function() {
       
    }
});




Aparentemente lo anterior usa información de la siguiente página:

John Resig - Simple JavaScript Inheritance


Y usa el siguiente código de inicialización (entenderlo queda de tarea; tal vez alguien más pueda ayudar a entenderlo, o veo si trato de estudiarlo al finalizar las lecciones disponibles, junto con el resto de elementos no explicados):
Código: Seleccionar todo
/* Simple JavaScript Inheritance
 * By John Resig http://ejohn.org/
 * MIT Licensed.
 */
// Inspired by base2 and Prototype
(function(){
  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;

  // The base Class implementation (does nothing)
  this.Class = function(){};
 
  // Create a new Class that inherits from this class
  Class.extend = function(prop) {
    var _super = this.prototype;
   
    // Instantiate a base class (but only create the instance,
    // don't run the init constructor)
    initializing = true;
    var prototype = new this();
    initializing = false;
   
    // Copy the properties over onto the new prototype
    for (var name in prop) {
      // Check if we're overwriting an existing function
      prototype[name] = typeof prop[name] == "function" &&
        typeof _super[name] == "function" && fnTest.test(prop[name]) ?
        (function(name, fn){
          return function() {
            var tmp = this._super;
           
            // Add a new ._super() method that is the same method
            // but on the super-class
            this._super = _super[name];
           
            // The method only need to be bound temporarily, so we
            // remove it when we're done executing
            var ret = fn.apply(this, arguments);       
            this._super = tmp;
           
            return ret;
          };
        })(name, prop[name]) :
        prop[name];
    }
   
    // The dummy class constructor
    function Class() {
      // All construction is actually done in the init method
      if ( !initializing && this.init )
        this.init.apply(this, arguments);
    }
   
    // Populate our constructed prototype object
    Class.prototype = prototype;
   
    // Enforce the constructor to be what we expect
    Class.prototype.constructor = Class;

    // And make this class extendable
    Class.extend = arguments.callee;
   
    return Class;
  };
})();
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mié Feb 06, 2013 12:41 am

Un detalle interesante de la clase es la mención del formato Web-p, que combina la capacidad de JPEG para comprimir ampliamente imágenes (probablemente sea compresión lossy), y capacidad de transparencia variable, como los PNG (que no se soporta por JPEG, obviamente).

Web-p o WebP me suena como el formato hermano de WebM.

WebP para "Web Picture" y WebM para "Web Multimedia".
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mié Feb 06, 2013 3:14 am

El cuarto y último ejercicio, de la lección sobre Canvas, es esto:

Animación de Robot


Este código se evaluó como malo a pesar de ser extremadamente robusto, y en su lugar se evaluó bien el siguiente código, pero que es inservible en el mundo real:

Animación de Robot (Código Malo en la Práctica)


Aquí usé el truco de reescribir la propiedad width o height del Canvas, para borrar la imagen anterior, para que no quede una superpuesta en la otra de manera fea, sin restaurar nuestro fondo vacío, como debería ser.

Ahora prácticamente queda solamente estudiar adicionalmente todo lo que no se ha explicado, pero se ha usado, en las lecciones.


Código: Seleccionar todo
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
  <title>Ejemplo de Canvas</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 </head>


<body id="body">

</body>


<script type="text/javascript">
//<![CDATA[



var canvas = null;
var context = null;
var assets = ['./media/js/standalone/libs/gamedev_assets/robowalk/robowalk00.png',
           './media/js/standalone/libs/gamedev_assets/robowalk/robowalk01.png',
           './media/js/standalone/libs/gamedev_assets/robowalk/robowalk02.png',
           './media/js/standalone/libs/gamedev_assets/robowalk/robowalk03.png',
           './media/js/standalone/libs/gamedev_assets/robowalk/robowalk04.png',
           './media/js/standalone/libs/gamedev_assets/robowalk/robowalk05.png',
           './media/js/standalone/libs/gamedev_assets/robowalk/robowalk06.png',
           './media/js/standalone/libs/gamedev_assets/robowalk/robowalk07.png',
           './media/js/standalone/libs/gamedev_assets/robowalk/robowalk08.png',
           './media/js/standalone/libs/gamedev_assets/robowalk/robowalk09.png',
           './media/js/standalone/libs/gamedev_assets/robowalk/robowalk10.png',
           './media/js/standalone/libs/gamedev_assets/robowalk/robowalk11.png',
           './media/js/standalone/libs/gamedev_assets/robowalk/robowalk12.png',
           './media/js/standalone/libs/gamedev_assets/robowalk/robowalk13.png',
           './media/js/standalone/libs/gamedev_assets/robowalk/robowalk14.png',
           './media/js/standalone/libs/gamedev_assets/robowalk/robowalk15.png',
           './media/js/standalone/libs/gamedev_assets/robowalk/robowalk16.png',
           './media/js/standalone/libs/gamedev_assets/robowalk/robowalk17.png',
           './media/js/standalone/libs/gamedev_assets/robowalk/robowalk18.png'
          ];

var frames = [];

var imgNum=0;
var loaded=new Array();
var done=false;


var onImageLoad = function(){
   console.log("IMAGE "+imgNum+"!!!");
    loaded[imgNum]=true;
    imgNum++;
};

var setup = function() {
   body = document.getElementById('body');
   canvas = document.createElement('canvas');

   context = canvas.getContext('2d');
   
   canvas.width = 100;
   canvas.height = 100;

   body.appendChild(canvas);

   // Load each image URL from the assets array into the frames array
   // in the correct order.
   // Afterwards, call setInterval to run at a framerate of 30 frames
   // per second, calling the animate function each time.
   // YOUR CODE HERE
    _LOAD_THR_=setInterval(function(){LoaderThread()}, 0);

};


var animating=false;

var animate = function(){
   // Draw each frame in order, looping back around to the
   // beginning of the animation once you reach the end.
    // Draw each frame at a position of (0,0) on the canvas.
   // YOUR CODE HERE
 if(animating || done!=true)return;
 animating=true;

  if(imgNum>=frames.length)imgNum=0;
   canvas.width=canvas.width;
   context.drawImage(frames[imgNum], 0, 0);
   imgNum++;

 animating=false;
};




var loading=false;

function LoaderThread()
{//alert("ld");
 if(loading)return;
 loading=true;

  if(imgNum>=assets.length)
  {
   imgNum=0;
   clearInterval(_LOAD_THR_);
   done=true;
   for(var x=0; x<assets.length; x++)
    done&=loaded[x];
  }


     if(loaded[imgNum]!=true && frames[imgNum]==undefined)
     {
       frames[imgNum]=new Image();
       frames[imgNum].onload=onImageLoad;
       frames[imgNum].src=assets[imgNum];
     }

 loading=false;
}


var _LOAD_THR_=null;
var _ANIM_THR_=null;
setup();

_ANIM_THR_=setInterval(animate, 1000/30);


//]]>
</script></html>
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mié Feb 06, 2013 8:05 pm

Este curso está basado en un juego para boilerplate interactivo de HTML5 basándose principalmente en tecnología de Google (Chrome), llamado GRITS:

Código de GRITS
https://code.google.com/p/gritsgame/source/checkout


Descargar GIT para diferentes plataformas
http://git-scm.com/downloads

Demo de GRITS corriendo
https://code.google.com/p/gritsgame/
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mié Feb 06, 2013 8:11 pm

Fundamentos de GIT

GIT es un programa multiplataforma para administrar versiones de programas en repositorios.

Sus funciones principales son:

- Crear repositorios nuevos.

- Abrir repositorios existentes.

- Clonar repositorios existentes (desde Internet).

Para nuestros propósitos, simplemente necesitamos clonar el repositorio de GRITS.
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mié Feb 06, 2013 8:28 pm

Guía de GIT para Windows

Paso 1
Descargamos GIT para Windows y lo instalamos con valores predeterminados
http://git-scm.com/download/win

Para otras plataformar ir a:
http://git-scm.com/downloads

1

1

1

1

1



Paso 2
Usar el menú contextual
1



Paso 3
Elegir "Clonar" en la GUI de GIT
1



Paso 4
Clonar el repositorio deseado en un nuevo directorio
1
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mié Feb 06, 2013 8:34 pm

El siguiente paso es determinar qué parte de GRITS hemos estudiado hasta ahora en el curso.

Después copiar y guardar el resto del programa del curso, e igualmente determinar qué partes del código fuente (del cliente y el servidor) corresponden a cada lección del curso.

Por ahora todo lo que hemos visto corresponde al lado cliente, y aparentemente, solo es para evaluar si sabemos todo lo necesario para continuar con facilidad el resto del curso.
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mié Feb 06, 2013 8:50 pm

Una vez clonemos localmente el repositorio GIT de GRITS, tendremos 41.4 Megabytes de datos, en 212 archivos y 57 directorios.

Solo 18.7 Megabytes son de audio e imágenes, con 33 archivos y 2 directorios, en:
./src/client/img/
./src/client/sound/

Otros 19.9 Megabytes son del subdirectorio oculto .git, con 24 archivos y 15 subdirectorios.

Los 2.8 Megabytes son el código pero también otras cosas, que deberíamos discriminar.

Hay 155 archivos y 40 subdirectorios restantes.

El resto de ./src/client/ tiene 1.13 Megabytes, 56 archivos y 10 subdirectorios, así que quedan 99 archivos y 30 subdirectorios.
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mié Feb 06, 2013 10:28 pm

Más importante que las estadísticas de tamaños, archivos y subdirectorios, es hacer una lista de funciones, variables, APIs, trucos, snippets y virutas del repositorio, y comenzar a asociarlas e investigar de forma simple los conceptos del programa:

Transcripciones
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mié Feb 06, 2013 10:47 pm

Por lo menos en la versión formal del juego ya corriendo, en http://gritsgame.appspot.com/, se están usando los scripts de jQuery, YepNope y MrDoob-Stats.

No sé todavía para qué se usan exactamente.
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Jue Feb 07, 2013 3:07 am

Foro:
https://forums.udacity.com/tags/cs255/#cs255


Tema: Videos faltantes de lección de JavaScript:
https://forums.udacity.com/questions/10 ... kage#cs255

Otros Temas
http://forums.udacity.com/questions/100 ... ge=2#cs255
https://forums.udacity.com/questions/10 ... ge=1#cs255
https://forums.udacity.com/questions/10 ... nits#cs255
https://forums.udacity.com/questions/10 ... work#cs255
https://forums.udacity.com/questions/10 ... ring#cs255
http://forums.udacity.com/questions/100 ... nits#cs255
https://forums.udacity.com/questions/10 ... sson#cs255
https://forums.udacity.com/questions/10 ... nejs#cs255
https://forums.udacity.com/questions/10 ... rect#cs255
http://forums.udacity.com/questions/100 ... aded#cs255
https://forums.udacity.com/questions/10 ... #100019632
https://forums.udacity.com/questions/10 ... king-robot
https://forums.udacity.com/questions/10 ... ages#cs255
https://forums.udacity.com/questions/10 ... t-it#cs255
https://forums.udacity.com/questions/10 ... rect#cs255
https://forums.udacity.com/questions/10 ... sson#cs255
https://forums.udacity.com/questions/10 ... tion#cs255
https://forums.udacity.com/questions/10 ... oday#cs255
https://forums.udacity.com/questions/10 ... ents#cs255
https://forums.udacity.com/questions/10 ... #100022397
https://forums.udacity.com/questions/10 ... -far#cs255
https://forums.udacity.com/questions/10 ... ames#cs255
https://forums.udacity.com/questions/10 ... #100022516
https://forums.udacity.com/questions/10 ... uest#cs255
https://forums.udacity.com/questions/10 ... dule#cs255
https://forums.udacity.com/questions/10 ... ries#cs255
https://forums.udacity.com/questions/10 ... more#cs255
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Lun Feb 11, 2013 5:12 am

Ya que vamos a usar WebAudio, necesitamos su especificación preliminar:

Web Audio API; W3C Editor's Draft
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Dom Feb 17, 2013 6:51 pm

Lección 3: Atlas

Los atlas parecen ser grandes imágenes que contienen un arreglo de todas las imágenes que usaremos en el juego, sean de nuestros personajes o del fondo.

Por razones de eficiencia de red, es mejor descargar una única imagen que muchas imágenes separadas para el juego.

Inicialmente yo creí que esto se trataba de imágenes que definían un mapa de fondo con alguna característica curiosa que permitía administrar su movimiento y despliegue, aunque parece estar relacioado de cierta forma, pero ser más que eso.

Esto es aún más así porque cada imagen del atlas está descrita por un archivo de texto o binario (o en este caso, un archivo JSON) que define el nombre de archivo, su posición en el atlas, su altura y anchura, y un offset negativo que describe el punto más central de la imagen en pixeles, a partir de su posición inicial en el atlas.


Problema 1

El primer problema es realmente fácil de resolver. Simplemente nos pide que recorramos cada definición de datos de archivo de los datos JSON, y los convirtamos a un objeto más "nativo" de JavaScript, definiendo su nombre, altura y anchura, posición X y Y en el atlas, y punto central de la imagen.

Lo más "difícil" es calcular el punto central basándonos en la altura y anchura de la imagen, dividiéndola entre 2 y asignándole un offset negativo para retroceder, como pide el problema.
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Dom Feb 17, 2013 6:59 pm

Problema 2

Este problema es un poco más complejo, porque requiere saber qué estructura tienen los datos.

Lo primero que nos va a confundir es que en el archivo spritesheet.js se define la clase SpriteSheetClass, pero no sabemos cómo usarla realmente.

Por ahora solo sabemos que usa la emulación de clases de John Resig (http://ejohn.org/blog/simple-javascript-inheritance/), así que desde ahí podemos ver que para usar esta clase, simplemente debemos usar algo como:
Código: Seleccionar todo
var spriteClass=new SpriteSheetClass();



Y esto hará que spriteClass sea una variable de tipo Object, conteniendo todas las funciones y variables internas a una clase.

Variables
img
url
sprites



Funciones
init
load
defSprite
parseAtlasDefinition
getStats






Sabiendo esto, ahora necesitamos saber en qué secuencia inicializar los datos, y cómo accederlos.

Primero necesitaríamos definir algunas variables para nuestro propio uso personalizado:
Código: Seleccionar todo
var jsonSprites;
var spriteClass;




Ahora necesitaríamos una petición XMLHttpRequest para obtener los datos JSON:
Código: Seleccionar todo
var x=new XMLHttpRequest();

x.open("GET", "grits_effects.json", true);


x.onload=function()
{
 if(this.readyState==4)
 {
  //ATENCIÓN: En este punto agregaremos el resto de código
  //          en esta explicación.
 }
};

x.send(null);




Ahora agregaremos código a la función onload del XMLHttpRequest. Comenzaremos por crear una nueva instancia de SpriteSheetClass, y completar los datos iniciales con parseAtlasDefinition:
Código: Seleccionar todo
spriteClass=new SpriteSheetClass();
 spriteClass.parseAtlasDefinition(this.responseText);








En este punto, ya tenemos definida la variable global gSpriteSheets (de tipo Object, no un arreglo en este punto, sino que un simple objeto). Sin embargo, recordemos que un objeto en JavaScript se puede considerar un arreglo asociativo con otra sintaxis, y esta variable precisamente será un arreglo de objetos a diferentes "hojas de sprites" (¿atlas?), cada elemento del arreglo siendo una instancia separada de nuestra SpriteSheetClass, porque podemos definir un "arreglo asociativo" con la sintaxis de objetos. Algo como:
Código: Seleccionar todo
var gSpriteSheets = {

  "sprite_url_0000.png":0  //Este podría ser uno o más objetos anidados

};



En este punto:

  • spriteClass.img es null.

  • spriteClass.url es una cadena vacía, "".

  • spriteClass.sprites es un arreglo de 781 (en este caso particular, aunque puede ser cualquier número entre 0 y N) Objects. Los índices del arreglo se seleccionan con índices entre 0 a 780. Cada objeto tiene las propiedades "id", "x", "y", "w", "h", "cx", "cy".


En este punto, ya hemos usado de una u otra forma las funciones init, defSprite y parseAtlasDefinition.

La función getStats simplemente nos dice si un sprite está definido, basado en su nombre, así que no es preocupación.

Lo que sí debemos saber cómo usar en teoría es la función load, que:

  • Inicializa la variable de clase url con la ruta de la imagen.

  • Crea una nueva imagen, asignándole la URL.

  • Guarda ese puntero al objeto de imagen en la variable de claseimg.

  • Guarda el puntero de toda la clase entera en el arreglo asociativo gSpriteSheets["ruta_imagen"], definido como variable global.



En teoría, para llevar a cabo los puntos anteriores, solo necesitaríamos ejecutar algo como:
Código: Seleccionar todo
spriteClass.load("/ruta/a/nuestra/imagen.png");



Y una vez cargada la imagen, la función anterior incluirá este objeto del cual forma parte en el arreglo asociativo global de "spritesheets".
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Dom Feb 17, 2013 8:09 pm

Ahora necesitamos completar la función:

drawSprite(spritename, posX, posY)

posX y posY son posiciones que pertenecen a los límites del Canvas.

spritename es el campo id proveniente del JSON. Esto lo determinamos viendo qué dato usa getStats como parámetro, dado que debemos usar esa función en drawSprite.

Si lo pensamos cuidadosamente, esta es una función de API diseñada para ser simple. Dado que la función pertenece a una instancia de la clase de sprites, y esta contiene un atlas completo, esta función individual está diseñada para tomar el nombre de sub-imagen deseada en dicho atlas, y la posición X y Y en donde queremos dibujarla en el Canvas, básicamente lo mismo que la siguiente imagen de tipo atlas:
AVS.PNG


Sin embargo, esta función podría ser mucho más eficiente si además del nombre del sprite dentro del atlas, también pidiera el nombre del atlas, porque la forma en que funciona actualmente requiere que recorramos cada elemento del arreglo de objetos de instancia sprite, y buscar el nombre del sprite (sub-imagen), algo demasiado lento, inaceptablemente lento, para lo que debería ser capaz de hacer, como lo que acabo de describir.

Código: Seleccionar todo
// External-facing function for drawing sprites based
// on the sprite name (ie. "chaingun.png", and the
// position on the canvas to draw to.
function drawSprite(spritename, posX, posY) {
   // Walk through all our spritesheets defined in
    // 'gSpriteSheets' and for each sheet:
    //
    // 1) Use the getStats method of the spritesheet
    //    to find if a sprite with name 'spritename'
    //    exists in that sheet.
    //
    // 2) If we find the appropriate sprite, call
    //    '__drawSpriteInternal' with parameters as
    //    described below.
    //
    // YOUR CODE HERE
    var ret=undefined;
     for(var gObjSpr in gSpriteSheets)
     {
      var spr;

      if(typeof(gSpriteSheets[gObjSpr])=="object" && typeof(gSpriteSheets[gObjSpr].getStats)=="function")
      if((spr=gSpriteSheets[gObjSpr].getStats(spritename))!=null)
      {
       //__drawSpriteInternal(spt, sheet, posX, posY)
       ///
        //__drawSpriteInternal(gObjSpr.sprites.spritename, gObjSpr, posX, posY);
        ret=__drawSpriteInternal(spr, gSpriteSheets[gObjSpr], posX, posY);
      }
     }

 return ret;
}


Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Dom Feb 17, 2013 9:34 pm

Y la función que realmente se encarga de dibujar un sprite de un atlas:

Código: Seleccionar todo
//-----------------------------------------
// External-facing function for drawing sprites based
// on the sprite object stored in the 'sprites Array,
// the 'SpriteSheetClass' object stored in the
// 'gSpriteSheets' dictionary, and the position on
// canvas to draw to.
function __drawSpriteInternal(spt, sheet, posX, posY) {
   // First, check if the sprite or sheet objects are
    // null.
    //
    // YOUR CODE HERE
     if(spt==null || sheet==null)return undefined;
   
   
    // Call the drawImage method of our canvas context
    // using the full drawImage API. drawImage takes,
    // in order:
    //
    // 1) the Image object to draw, this is our entire
    //    spritesheet.
    //
    // 2) the x-coordinate we are drawing from in the
    //    spritesheet.
    //
    // 3) the y-coordinate we are drawing from in the
    //    spritesheet.
    //
    // 4) the width of the sprite we are drawing from
    //    our spritesheet.
    //
    // 5) the height of the sprite we are drawing from
    //    our spritesheet.
    //
    // 6) the x-coordinate we are drawing to in our
    //    canvas.
    //
    // 7) the y-coordinate we are drawing to in our
    //    canvas.
    //
    // 8) the width we are drawing in our canvas. This
    //    is in case we want to scale the image we are
    //    drawing to the canvas. In our case, we don't.
    //
    // 9) the height we are drawing in our canvas. This
    //    is in case we want to scale the image we are
    //    drawing to the canvas. In our case, we don't.
    //
    // Wow, that's a lot of parameters. Luckily, most
    // of them are stored directly in the sprite object
    // we want to draw.
    //
    // YOUR CODE HERE
//     sheet.drawImage(spt, posX, posY, spt.width, spt.height);
/*
     ctx.drawImage(sheet,
                   startclipX,
                   startclipY,
                   spt.width,
                   spt.height,
                   posX,
                   posY,
                   spt.width,
                   spt.height);
*/
/*
     ctx.drawImage(sheet, //ERROR: I should be more aware of the types
                   spt.x, //       of the variables and data I'm using.
                   spt.y, //       It should have been sheet.img, because
                   spt.w, //       sheet is an object, an instance of the
                   spt.h, //       sheeting class.
                   posX,
                   posY,
                   spt.w,
                   spt.h);
*/
     ctx.drawImage(sheet.img,
                   spt.x,
                   spt.y,
                   spt.w,
                   spt.h,
                   posX+spt.cx,  //Why? Because the game passes
                   posY+spt.cy,  //a center point to this function,
                   spt.w,        //so the sprite, no matter its size,
                   spt.h);       //is treated as a little dot, centrally.

 return true;
};

//Still this code was too slow: 720 milliseconds to complete for just 2
//images!

Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Lun Feb 18, 2013 1:21 am

Problema 3

Este problema nos pide manipular imágenes a las que se les recortó toda el área de los bordes que tenía solo color de fondo (es decir, un área vacía de imagen eliminada).

Lo que nos piden es ver si los datos indican que la imagen ha sido recortada de esta forma, y si es así, recalcular el centro con respecto a su centro original, no a las esquinas (cx y cy, o cornerX y cornerY) de la imagen recalculada.





Lo primero que me pregunto es por qué no simplemente usar la mitad de la imagen original sin recortar y ya, pero al parecer eso no se hace porque la imagen puede no realmente estar en el centro absoluto del área de fondo sin recortar.

Así que no estaríamos hablando de un centro absoluto, sino de algo similar, pero que requiere cálculo más complicado.
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Lun Feb 18, 2013 2:53 am

Necesito recordar lo que estaba pensando originalmente, porque lo que escribí cuando tenía la mente fresca era esto:

Código: Seleccionar todo
var trimW=(parsed.frames[key].sourceSize.w-parsed.frames[key].spriteSourceSize.w)>>1;
var trimH=(parsed.frames[key].sourceSize.h-parsed.frames[key].spriteSourceSize.h)>>1;



Y la respuesta correcta es básicamente la siguiente fórmula:

Código: Seleccionar todo
cx=(parsed.frames[key].spriteSourceSize.x)-(parsed.frames[key].sourceSize.w>>1);
cy=(parsed.frames[key].spriteSourceSize.y)-(parsed.frames[key].sourceSize.h>>1);



Esto demuestra que aunque el código inicial esté malo, el que escribí cuando acababa de ver el problema por primera vez y cuando tenía la mente fresca, la lógica que este contiene siempre será la más cercana a la respuesta correcta.
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Lun Feb 18, 2013 3:04 am

Parece que lo que estaba pensando era obtener el tamaño completo original del fondo sin recortar en altura y anchura, y a esto restarle el tamaño de altura y anchura solamente del área válida de la imagen, y todo esto dividirlo entre 2 para tener un punto central.

Pero resulta que la respuesta correcta, en primer lugar, exige que me asegure de que el valor resultante sea negativo, así que tengo que ya sea asegurarme de restarle el valor mayor al número menor, o restarle el valor menor al número mayor y después cambiar a signo negativo.

Código: Seleccionar todo
cx=-((parsed.frames[key].sourceSize.w>>1)-parsed.frames[key].spriteSourceSize.x);
cy=-((parsed.frames[key].sourceSize.h>>1)-parsed.frames[key].spriteSourceSize.y);



O:

Código: Seleccionar todo
cx=(parsed.frames[key].spriteSourceSize.x-(parsed.frames[key].sourceSize.w>>1));
cy=(parsed.frames[key].spriteSourceSize.y-(parsed.frames[key].sourceSize.h>>1));




O:

Código: Seleccionar todo
cx=((parsed.frames[key].sourceSize.w>>1)-parsed.frames[key].spriteSourceSize.x);
cy=((parsed.frames[key].sourceSize.h>>1)-parsed.frames[key].spriteSourceSize.y);

if(cx>=0)cx*=-1;
if(cy>=0)cy*=-1;

Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Lun Feb 18, 2013 3:18 am

Aquí se aplica el hecho del que estaba hablando, de el por qué no simplemente usar la mitad de la altura y anchura del fondo original, aunque realmente lo hacemos aquí.

Habría sido cuestión de probar las 3 posibilidades: dividir todo (erróneo), dividir el tamaño del fondo sin recortar (correcto), o dividir el tamaño de la imagen recortada (incompleto, porque en lugar de eso debería haber usado las posiciones X y Y de esta imagen recortada).

El hecho de tener que usar esos valores de X y Y es la respuesta a mi pregunta, de que realmente no estamos buscando una imagen centrada (porque hay ocasiones en las que habrá pixeles muy cerca del borde, y eso hace que sea más conveniente usar los valores de X y Y).

Después de restarle al tamaño de la mitad de fondo la posición X y Y inicial (o viceversa, restarle a las posiciones X/Y iniciales el valor de la mitad de altura y anchura del fondo), debo asegurarme de que estos valores, para el cx y el cy sean negativos.
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Lun Feb 18, 2013 4:06 am

Así que aparentemente la intención es asumir que tenemos el tamaño de nuestro fondo original completo.

A este fondo normalmente asumiremos que ya está en el punto central de un punto X/Y cualquiera, y por lo tanto conocemos visualmente su centro (como esta es el área principal, es a esta la que dividimos entre 2 en altura y anchura, para obtener su punto central).

La intención de restarle el valor de X/Y de la imagen en cuestión con fondo rellenado es, dada una coordenada X/Y a la cual dibujar, retroceder la posición X/Y inicial para buscar el centro de ese punto, tomando en cuenta el tamaño de la imagen original sin recortar.


Por ejemplo si se nos pide dibujar en la posición 0,0 y nuestros valores de centro son -26 y -32, y si el tamaño de nuestra imagen efectiva en cuestión es 42x34, terminaríamos dibujando solo una imagen de 16x2, que se supone representa el punto más central de la imagen efectiva dentro del fondo sin rellenar.
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Lun Feb 18, 2013 5:08 am

Personalmente preferiría asegurarme de crear sprites con un centro absoluto desde el principio, asegurándome también de que el fondo vacío de estas quede totalmente recortado. También usaría imágenes empacadas en un único archivo (paquete), lo que haría posible evitar usar un atlas a menos que sea absolutamente necesario por algún requerimiento exótico.

Toda la explicación anterior seguramente fue confusa de entender, y aparentemente para poder entender el empacado de texturas no hay más remedio que familiarizarse y usar el Texture Packer (Empacador de Texturas), y llegar a tener una idea intermedia del algoritmo, o una idea clara para replicar el algoritmo (y por lo tanto entenderlo tanto como entenderíamos los algoritmos de un formato de archivo gráfico):

Texture Packer

Búsqueda en Google: texture packing





Otros Recursos

Necesitaremos otros recursos para comenzar a prepararnos y a tener idea de los conceptos que conocemos menos, y que serán parte de las subsiguientes clases:

Búsqueda en Google sobre "Box2D" (motor de simulación física)

Búsqueda en Google sobre Box2D para JavaScript

Página de SourceForge para Box2DJS (JavaScript)

Búsqueda en Google sobre jerarquía de entidades (entity hierarchy).

Entity Hierarchy (parenting) - Valve Developer Community
Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm

Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Mar Feb 19, 2013 5:57 pm

Ahora pongo un ejemplo de la animación anterior del robot que se puede controlar con las teclas de flechas de desplazamiento del teclado:

>>Ejemplo de Animación Controlable<<


Por ahora, esto es lo máximo que se puede lograr en la práctica usando exclusivamente el conocimiento básico de los prerrequisitos y lo enseñado en la clase.

Lo más interesante es el uso de event.preventDefault(); para hacer que apretar o soltar teclas como F5, Ctrl+W, u otros, incluso Alt+F4 para cerrar la ventana, no tengan absolutamente ningún efecto predeterminado mientras estemos en esa pestaña del navegador, capturando así por completo el comportamiento de las teclas no especiales. Las teclas no capturadas son la tecla de Windows, la del menú contextual, PrnScr, las teclas Multimedia y ACPI (apagar, suspender), y combinaciones especiales de sistema como Alt+Tab para cambiar entre ventanas, ni Ctrl+Esc, que tiene el mismo efecto de la tecla Windows, ni Alt+SpaceBar para desplegar el menú de sistema, como si diéramos clic en el icono de la ventana, en el extremo izquierdo superior de esta, en la barra de título.

Usamos solamente el estado inicial de teclas apretadas o soltadas en lugar de responder cada vez que se produce el evento de repetición usando una bandera que activamos cuando se apreta una tecla, y que desactivamos cuando se suelta, para provocar el inicio y el final de la aplicación del efecto de desplazamiento correspondiente; de esta forma no nos veremos afectados por la velocidad de repetición del teclado, como debería ser, y como funcionan todos los juegos clásicos y modernos que conocemos, hablando de la entrada del teclado.

Código: Seleccionar todo
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
 <title>Animación Controlable de Ejemplo</title>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body onload="setup();" id="body">
</body>







<script type="text/javascript">
var canvas = null;
var context = null;
var xCoord = 0;
var xDirection = 1;
var yCoord = 0;
var yDirection = 1;


var LEFTACTIVE=false;
var RIGHTACTIVE=false;
var UPACTIVE=false;
var DOWNACTIVE=false;




var assets = ['http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk00.png',
              'http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk01.png',
              'http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk02.png',
              'http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk03.png',
              'http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk04.png',
              'http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk05.png',
              'http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk06.png',
              'http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk07.png',
              'http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk08.png',
              'http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk09.png',
              'http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk10.png',
              'http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk11.png',
              'http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk12.png',
              'http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk13.png',
              'http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk14.png',
              'http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk15.png',
              'http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk16.png',
              'http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk17.png',
              'http://www.udacity.com/media/js/standalone/libs/gamedev_assets/robowalk/robowalk18.png'];

var frames = [];
var imgNum=0;
var loaded=new Array();
var done=false;



var onImageLoad = function(){
   console.log("IMAGE "+imgNum+"!!!");
    loaded[imgNum]=true;
    canvas.width=canvas.width;
    context.drawImage(frames[imgNum], xCoord, yCoord);
    imgNum++;
};

var setup = function() {
   body = document.getElementById('body');
   canvas = document.createElement('canvas');

   context = canvas.getContext('2d');
   
   canvas.width = 500;
   canvas.height = 500;

    canvas.style.backgroundColor="lightgray";

   body.appendChild(canvas);
    canvas.setAttribute("tabIndex",1);
    canvas.focus();

    document.addEventListener('keydown', downKey, false);
    document.addEventListener('keyup', upKey, false);


   // Load each image URL from the assets array into the frames array
   // in the correct order.
   // Afterwards, call setInterval to run at a framerate of 30 frames
   // per second, calling the animate function each time.
   // YOUR CODE HERE
    _LOAD_THR_=setInterval(function(){LoaderThread()}, 0);

};


var animating=false;

var animate = function(){
   // Draw each frame in order, looping back around to the
   // beginning of the animation once you reach the end.
    // Draw each frame at a position of (0,0) on the canvas.
   // YOUR CODE HERE
 if(animating || done!=true)return;
 animating=true;




  if(imgNum>=frames.length)imgNum=0;
   canvas.width=canvas.width;




   offsetMover();

   xCoord+=xDirection;
   if(!(xCoord>=0 && xCoord<(500-83)))
   xDirection*=-1;

   yCoord+=yDirection;
   if(!(yCoord>=0 && yCoord<(500-83)))
   yDirection*=-1;









   context.drawImage(frames[imgNum], xCoord, yCoord);
   imgNum++;





 animating=false;
};





function upKey(event)
{
 var scanCode=event.keyCode;

 if(scanCode==38)//Up
 UPACTIVE=false;

 if(scanCode==40)//Down
 DOWNACTIVE=false;

 if(scanCode==37)//Left
 LEFTACTIVE=false;

 if(scanCode==39)//Right
 RIGHTACTIVE=false;


 if(!done)
   offsetMover();

 event.preventDefault();
 return false;
}





function downKey(event)
{
 var scanCode=event.keyCode;

 if(scanCode==38)//Up
 UPACTIVE=true;

 if(scanCode==40)//Down
 DOWNACTIVE=true;

 if(scanCode==37)//Left
 LEFTACTIVE=true;

 if(scanCode==39)//Right
 RIGHTACTIVE=true;


 if(!done)
   offsetMover();

 event.preventDefault();
 return false;
}





function offsetMover()
{
 if(UPACTIVE)//Up
 {
  if(yCoord>=0)
  {
   yDirection=-1;
   yCoord+=yDirection;
  }
 }


 if(DOWNACTIVE)//Down
 {
  if(yCoord<(500-83))
  {
   yDirection=1;
   yCoord+=yDirection;
  }
 }



 if(LEFTACTIVE)//Left
 {
  if(xCoord>=0)
  {
   xDirection=-1;
   xCoord+=xDirection;
  }
 }



 if(RIGHTACTIVE)//Right
 {
  if(xCoord<(500-83))
  {
   xDirection=1;
   xCoord+=xDirection;
  }
 }



}













var loading=false;

function LoaderThread()
{
 if(loading)return;
 loading=true;

  if(imgNum>=assets.length)
  {
   imgNum=0;
   clearInterval(_LOAD_THR_);
   done=true;
   for(var x=0; x<assets.length; x++)
    done&=loaded[x];

    if(done)
     _ANIM_THR_=setInterval(animate, 1000/30);
  }


     if(loaded[imgNum]!=true && frames[imgNum]==undefined)
     {
       frames[imgNum]=new Image();
       frames[imgNum].onload=onImageLoad;
       frames[imgNum].src=assets[imgNum];
     }

 loading=false;
}


var _LOAD_THR_=null;
var _ANIM_THR_=null;

//_ANIM_THR_=setInterval(animate, 1000/30);

</script>



</html>

Imagen
IP for hosts file (email udocproject@yahoo.com to get updates if website becomes offline):
Código: Seleccionar todo
190.150.9.244 archefire.org



See what I'm doing in real time:
Main Desktop 1
Main Desktop 2
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm


Re: [Udacity]CS255: Desarrollo de un Juego en HTML5

Notapor ~ » Jue Feb 28, 2013 12:45 pm

Lección 4: Mapas

Esta semana se extendió la lección sobre Atlas para hablar sobre Mapas, que representan el entorno del juego. Solamente se habló sobre cómo buscar un "azulejo" (es decir una sub-imagen del Mapa que corresponde a un fondo a dibujar).

Lastimosamente no se habló sobre técnicas concretas para desplazarse por el entorno, haciendo que solo parte de este sea visible a la vez, y dibujando la parte visible de forma acorde.





Dejando de lado el código y las variables/estructuras específicas de GRITS, el concepto más valioso (aunque muy básico en realidad, sin importar lo complicado que puedan parecer los ejercicios de esta semana), es cómo encontrar la posición de cada "azulejo" (sub-imagen), lo que implica usar la altura y anchura de dichos "azulejos" como la mínima unidad, en lugar de usar pixeles como la medida más pequeña.


Tal como podemos recordar del Emulador de VGA, el cual era capaz de mover el cursor de texto dado un índice entre 0 y 1999 (para un modo de texto de 80x25 con un total de 2000 celdas de caracteres en pantalla), el emulador, y de hecho las VGA reales, calculan las posiciones X y Y a partir del índice 0-1999 (dividiendo entre 80 que es la anchura X para el modo 80x25 por ejemplo para obtener la posición Y, y el residuo es la posición en X), y después este índice de celda X/Y lo convierten a un índice de pixel en la pantalla (multiplicando por 8 que es la anchura de caracteres en el modo de 80x25, con caracteres de 8 pixeles de anchura).

Esto es exactamente el cálculo más importante que se lleva a cabo en la lección de esta clase.






Explicación Extendida

Parece que lo primero que debemos entender es que firstgid es un índice que puede estar repartido a lo largo de varios tilesets (atlas).

Así que por ejemplo, podríamos tener un atlas con índices (gids) 1 a 100, y otro atlas con índices 101 a 200.

Por eso es que la fórmula efectuada es:

Código: Seleccionar todo
localID=tileIndex-firstgid



Lo que esto hace es establecer el índice deseado del "azulejo" (sub-imagen) a una base de 0, para hacer que el índice firstgid que está repartido potencialmente a través de varios atlas, a un índice local basado en cero.

Eso hace necesario verificar que el índice deseado sea menor que firstgid, y para verificar el límite inferior, comenzamos desde el atlas/tileset con el mayor firstgid, como se ve en la respuesta, yendo en un bucle hacia atrás a través de los diferentes tilesets.

_________________________________
_________________________________
Los otros cálculos parecen estar basados en el hecho conocido de que las coordenadas 2D, estén basadas en pixeles, o en unidades mayores, como en este caso, basadas en unidades de "azulejos" (tiles) completos, puede calcularse con:

Código: Seleccionar todo
(Offset_Y*Max_X)+X


Así que si volvemos a dividir entre Max_X el cual en este caso es NumXTiles, obtendremos un entero con un decimal. Si solo obtenemos la parte entera, volveríamos a obtener el Offset_Y (o en otras palabras, el número total de filas completas de "azulejos").

Y si obtenemos el residuo de esa división, ya sea restando la parte entera del total, o usando módulo, obtenemos el offset X, o en otras palabras, el número de "azulejos" que conforman una fila de "azulejos" incompleta.


_________________________________
_________________________________
Finalmente, para obtener los offsets X y Y en pixeles, simplemente multiplicamos el número de filas y columnas X y Y a mover, calculadas anteriormente, por el tamaño X y Y de un "azulejo" en pixeles, respectivamente.






Links Interesantes

TMX Map Format
Explica los diferentes campos de información contenidos en el archivo JSON para los ejercicios de esta semana, solo que en formato XML en lugar de JSON, pero es la misma referencia.


Map Editor
La herramienta usada para crear de forma automatizada el mapa (el de GRITS, y el de la lección de esta semana, que son lo mismo).






Opiniones Finales

El poder manejar de forma fácil el material tal como se ha dado en la clase, requiere acostumbrarse a usar Map Editor o herramientas similares.

Pero no solo eso, sino que también requiere ser un buen artista visual digital, o adquirir esas habilidades, con una visión de programador, para siquiera poder entender a cabalidad cómo diseñar los gráficos del entorno y de los elementos animados del juego, para poder siquiera definirlos como un mapa efectivo (esto es lo que realmente nos llevará tiempo entender, más allá del tiempo de la clase, y conceptos que no han sido enseñados en la clase).

No basta con ser un programador regular, sino también un artista digital con conocimiento y teoría funcional en este campo multimedia, como digo, para diseñar la interfaz del juego (tanto como al intentar implementar un sistema de ventanas desde cero y sin ayuda de Windows o de un servidor X, también necesitamos entender conceptos poco comunes, y programación de árboles binarios y conceptos similares, para poder llevar el control de elementos traslapados, botones, ventanas, y que los clics y eventos del usuario activen lo que deban activar).
Avatar de Usuario
~
Site Admin
 
Mensajes: 2958
Registrado: Sab Nov 10, 2012 1:04 pm


Volver a Cursos Interactivos

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 16 invitados


cron