Archivo de la categoría: Informática

Making of Anima: UNICO – Localización

Aquí estoy de nuevo. Hoy voy a hablar de un punto peliagudo: la localización, es decir, la traducción y paso a otros idiomas de la aplicación. Esto presenta varios problemas iniciales:

No puedo limitarme a traducir cada término: tengo que usar las equivalencias de las distintas ediciones internacionales. Por suerte, cuento con la ayuda de varios voluntarios (Vincent «Moklo» Bouscarle, corrector de la edición francesa de Anima, está traduciéndola al francés; Andrew «Dynaes» Reich, del foro inglés, está traduciéndola al inglés). De nuevo, muchas gracias a ambos. 

Como ya he mencionado, tengo básicamente tres capas en Anima: UNICO. La capa de modelo se encarga de organizar la información. El modelo de Personaje, por ejemplo, sabe almacenar el nombre, las habilidades, sabe cómo subir de nivel, etc. La capa de Controlador conoce los modelos y las vistas y gestiona toda la lógica general de la aplicación. Por ejemplo, el Controlador de artes marciales sabe cuánto le costará a un personaje en concreto un arte marcial en concreto, y qué datos necesitará una Vista para que el usuario pueda elegir un arte marcial. La capa de Vista recibe datos del Controlador y muestra lo que el usuario ve en la pantalla. Sólo para la Vista tiene sentido la localización.

Mi solución

function setIdiomaUI() {
   var lang = navigator.language || navigator.userLanguage;
   
   if ((lang.lastIndexOf("es") != -1) || (lang.lastIndexOf("spa") != -1)) {
      IDIOMA_UI = SPA;
   } else {
      IDIOMA_UI = ENG;
   }
}
function L(id, spa, eng) {
   this.id = id;
   this[SPA] = spa;
   this[ENG] = eng;
   if (!diccionario["ANIMAUNICO_"+this.id]) {
      diccionario["ANIMAUNICO_"+this.id] = this;
   } else {
      console.log("Clave de diccionario repetida: [" + this.id + " / " + this[SPA] + " / " + this[ENG] + "]");
      console.log("--Clave previa: [" + diccionario["ANIMAUNICO_"+this.id].id + " / " + diccionario["ANIMAUNICO_"+this.id][SPA] + " / " + diccionario["ANIMAUNICO_"+this.id][ENG] + "]");
   }
}
L.prototype = {
   constructor: L,
   toString : function() {
      return this[IDIOMA_UI];
   },
   getId : function() {
      return this.id;
   }
};
function _l(clave) {
   if (diccionario["ANIMAUNICO_"+clave]) {
      return diccionario["ANIMAUNICO_"+clave].toString();
   } else {
      return clave;
   }
}

Explicando un poco: creo una clase, L, que tendrá como instancias cada cadena a localizar y sus localizaciones. Además, tengo una función, _l, que recibe el identificador de una cadena y devuelve su localización al idioma actual. Internamente, las capas de modelo y de controlador sólo usan los identificadores de las cadenas, que son únicos. Cuando la capa Vista va a mostrar algún texto en pantalla, se asegura de mostrarlo llamando a la función _l.

La declaración de cadenas la realizo así:

var UI_DAÑO_FINAL = (new L("UI_DAÑO_FINAL","Daño final","Final Dmg.")).getId();
var UI_VELOCIDAD = (new L("UI_VELOCIDAD","Velocidad","Speed")).getId();
var UI_TURNO_FINAL = (new L("UI_TURNO_FINAL","Turno final","Final Init.")).getId();

Como se puede ver, esto es sólo para español e inglés. En cuanto añada la traducción al francés, me bastará con alterar la clase L y añadir la localización a cada cadena como un argumento más.

Como resulta claro enseguida, esta solución aún presenta problemas. Por ejemplo, habrá ocasiones en que la unión de varios términos deba hacerse en distinto orden según el idioma, y éste sistema de por sí no ofrece soporte para ese caso. Pero para el caso de una hoja de personaje, que sobre todo mostrará términos de manera aislada de momento me está funcionando bastante bien.

Progreso en Anima: UNICO

Hace ya una semana de la última actualización de Anima: UNICO. No es que lo haya dejado de lado, ni mucho menos. Simplemente, lo que estoy actualizando mes bastante costoso.
Estoy actualizando la sección de Técnicas del Ki a lo incluido en Dominus Exxet. Esto requiere repasar todos los efectos (algunos costes cambian), añadir los costes de sostenimiento, añadir el control de la clase de efectos (para saber qué desventajas son aceptables), implementar las reglas de sostenimiento y las de téecnicas combinables.
Además, estoy aprovechando para limpiar y mejorar la inmterfaz de usuario. La ventana que aparecía al darle a comprar algo referente al CM ahora desaparece, y cada elemento se compra directamente desde la hoja principal. Este cambio lo implementaré también más tarde para magia y para psíquica.
Y, como si fuera poco, estoy reorganizando la ventana de creación de técnicas.
Ya me falta poco para terminar todo esto. En unos días, como mucho, lo podréis disfrutar.

Making of Anima: UNICO – Estructura general

En la última entrada repasé las principales herramientas que estoy empleando para crear Anima: UNICO. He de añadir una que olvidé: SourceTree, una interfaz gráfica para git muy cómoda y agradable que permite seguir fácilmente el patrón GitFlow. Obviamente, no necesito usar GitFlow (y realmente no lo uso al 100%), pero como base para organizarme me gusta.

Y, ahora, pasaré a entrar en materia de verdad. Primero, ¿cómo organizar una aplicación javascript del tamaño de Anima: UNICO? Tras mis primeras exploraciones, llegué al siguiente flujo de trabajo:

  1. Creo tantos ficheros javascript como me sea cómodo, normalmente uno por clase.
  2. Para publicarlos, empleo Grunt para concatenarlos todos, minificarlos y ofuscarlos, y así obtengo un único archivo javascript para publicar en la web.

En cuanto al modo de organizar los archivos javascript, me he basado en patrones Modelo-Vista-Controlador

  • js/ – Carpeta general de archivos javascript
    • controller/ – Controladores.
    • data/ – Datos.
    • view/ – Vistas.
    • model/ – Modelos.
    • locale/ – Localización.
    • libs/ – Librerías de terceros
    • vendor/ – Librerías de terceros
  • sass/ – Ficheros SASS.
  • img/ – Imágenes
  • fonts/ – Fuentes
  • css/ – Ficheros CSS.
  • index.html – La página principal.
  • indexLocal.html – Versión de la página principal para depuración local.
  • Gruntfile.js – Instrucciones para Grunt.

Controladores

Se encargan de interacción entre modelos, de preparar los datos que se presentarán al usuario y de interpretar las acciones de usuario.

Datos

Los datos de las instancias concretas de cada clase. Es decir, los datos de cada ventaja,  conjuro, arte marcial, etc…

Hay varias formas de almacenar los datos. Como quería que la aplicación funcionara offline, no podía usar una base de datos. Al final, los almaceno en su propia inicialización. Esto es… mala idea. Debería haberlos guardado desde el principio en formato JSON, y en algún momento del futuro seguramente haga el cambio.

Un ejemplo:

addVentaja(new Ventaja( VENT_APRENDIZAJE_INNATO_EN_UN_CAMPO, «», VENT_APRENDIZAJE_INNATO_EN_UN_CAMPO_DESC, REPETIBLE_OPCIONES, [2,3], [], true, [LISTA_TIPOS_SECUNDARIAS], [aprendizajeInnatoCampo], GRUPO_SECUNDARIAS ));

Esta línea de código inicializa la ventaja «Aprendizaje innato en un campo».

Vistas

Las vistas son las encargadas de generar la interfaz de usuario y de interactuar con él.

Modelos

Los modelos son las clases básicas. Personaje, Raza, ArteMarcial, etc…

Localización

La localización es todo lo relacionado con mostrar la aplicación en varios idiomas. Actualmente esto incluye español e inglés, y el francés está en proceso. Cuento para este paso con la ayuda totalmente inestimable e imprescindible de Andrew «Dynaes» Reich y de Vincent «Moklo» Bouscarle.

En otro artículo entraré en detalle en cómo realizo la localización, ya que me parece un punto interesante.

Making of Anima: UNICO – Herramientas

Aquí estoy de nuevo. Como prometí, voy a hablar de las herramientas que uso para crear Anima: UNICO. Sin más…

1. Lenguaje: HTML+CSS+JavaScript en el cliente, PHP en el servidor

Ésta está clara. El desarrollo principal de Anima: UNICO está realizado en JavaScript. La página web en sí usa HTML, aunque la mayor parte de la misma se genera dinámicamente desde código usando jQuery. La representación se controla casi totalmente mediante CSS.

2. Frameworks y librerías de Javascript: jQuery, jQuery UI, Modernizr, Gumby

Una de los puntos fuertes de JavaScript es la gran cantidad de desarrollos existentes. Muy probablemente jQuery sea el más famoso de ellos, y con razón. Sus funciones resultan básicas para trabajar con el DOM de la página web y no volverse loco.

Además de jQuery, comencé utilizando jQuery UI como base para la interfaz de usuario. jQuery UI es un framework con funciones para crear botones, diálogos, componentes arrastrables, etc.

Modernizr es una pequeña librería que facilita el diseño para varios navegadores.

Gumby es un framework para crear web adaptativas, que se ajustan al tamaño de la pantalla de visualizado. Es la base con la que doy formato a la página.

3. Frameworks y librerías de PHP: CakePHP

Para el lado del servidor de momento estoy usando, de modo muy muy básico, CakePHP, que me ofrece de base justo lo que quería.

4. IDEs: Jetbrains WebStorm, JetBrains PHPStorm

Los IDEs de JetBrains me han conquistado. Me encantó WebStorm para desarrollar en JavaScript, y cuando empecé a usar PHP pasé a PHPStorm (que incluye toda la funcionalidad de WebStorm). Son entornos de desarrollo muy potentes, con integración con todo lo que necesitaba integrar (control de versiones, base de datos remota, ftp, librerías…).

Además, a través de estos IDEs descubrí todas las tecnologías del siguiente punto…

5. Muchas más: Node.JS/NPM+Grunt, SASS+Compass, Mocha

Los IDEs de JetBrains se integran con un servidor Node.JS propio, que permite cargar un montón de scripts de lo más útiles. Yo llegué hasta Grunt, que permite automatizar tareas (es similar a un Make), y lo usé para unificar mis archivos de javascript, minificarlos y prepararlos para ser publicados en producción.

6. Control de versiones

Empecé usando Subversion como control de versiones, pero hace unos meses descubrí y aprendí Git, y no he mirado atrás. Me parece un sistema genial de control de versiones.

7. Tareas, control general, repositorio: Assembla

Buscando, encontré varias opciones de repositorio online. Al final me decanté por Assembla, que ofrece un plan básico gratuito muy atractivo (para mi). Se integra con Svn y con Git, ofrece control de tareas y tickets (que puedo integrar con PHPStorm)

8. Informes y análisis de visitas: Google Analytics

En la página tengo Google Analytics para comprobar las visitas diarias, idioma de visitantes, navegador… detalles bastante importantes para un proyecto en JavaScript.

Por hoy es todo. El próximo día empezaré a describir la estructura básica del código.

Ah, por cierto, en GitHub podéis encontrar el repositorio de código. ¡Adelante, hacedle un fork o lo que queráis!

Configurar acceso remoto a una BBDD SQL Server

Este post va a ser tremendamente poco profesional, pero quizás a alguien le sirva de algo.

Se tiene una BBDD en un servidor SQL Server. Se quiere acceder remótamente, por ejemplo creando un acceso de datos ODBC desde otra máquina.

1) Ejecutar las herramientas de red de servidor en la máquina servidor. Habilitar el protocolo TCP/IP y fijar un puerto. Comprobar que dicho puerto está abierto en el firewall del servidor.

2) Ejecutar %windows%\system32\cliconfig.exe en el cliente. Habilitar el protocolo TCP/IP marcando detectar el puerto automáticamente. En la pestaña Alias, crear un alias para el servidor con un nombre distintivo. Marcar la opción TCP/IP, e indicar en acceso su IP.

3) En el cliente, crear el origen de datos ODBC indicando como servidor el alias creado.

EDITADO: Se me había olvidado que, evidentemente, hay que abrir también el puerto en el cliente.