Una de las cosas que llevo tiempo siguiendo –y persiguiendo– al meterme en los temas de programación y de la informática que tanto tiempo me ocupan, es la capacidad que tiene la tecnología para hacer juegos, crear mundos virtuales y la posibilidad que eso da de utilizar ese tipo de aplicaciones para mejorar el aprendizaje.
Quizá el haber tenido que aprender la lista de los reyes Godos cuando era joven, las tediosas tardes recitando nombre tras nombre, para olvidarlos nada más hacer el examen, me predisponga a perseguir el sueño de un aprendizaje más lúdico, más interesante. El aprenderme esa lista no me hizo más inteligente ni el haberla olvidado me hace más torpe (eso sí, sé quienes son las estatuas de la plaza de Oriente en Madrid, ciudad en la que residí durante veinticuatro años de mi vida).
El caso es que mientras cambiaba ayer mi móvil a android estuve mirando las aplicaciones que instalar y muchas más cosas. Empleando casi todo el día procrastinando entre unas y otras apps y viendo qué instalar y que desinstalar (si me dejaba) o dejaba inhabilitado, tropecé con la versión para android de Löve-2D. Hace un tiempo, cuando corría por la versión 0.8 ó 0.9 ya hice unas pruebas con él, pero sólo para PC (GNU/linux y güindón).
El código
Pego aquí el código en Lua para hacer ese ejercicio. No es mi objetivo explicar todo lo que hace. De todas formas, creo que puse suficientes comentarios, lo suelo hacer porque soy muy torpe y al cabo del tiempo después de haber escrito el código muchas veces no tengo claro qué hace. Por eso uso los comentarios como un guiaburros de lo que pienso cuando lo escribo.
function love.load()
love.physics.setMeter(50) --el largo de un metro en nuestro mundo será de 50px
world = love.physics.newWorld(0, 9.81*50, true) --creamos un mundo para los cuerpos con una gravedad horizontal de 0 y de 9.81 en vertical
objects = {} -- tabla donde guardar los objetos físicos
--creamos un clavo
objects.clavo = {}
objects.clavo.body = love.physics.newBody(world, 425, 200)
objects.clavo.shape = love.physics.newRectangleShape(10, 10)
objects.clavo.fixture = love.physics.newFixture(objects.clavo.body, objects.clavo.shape)
--creamos un par de bolas que harán de pesos de los péndulos
objects.bola1 = {}
objects.bola1.body = love.physics.newBody(world, 525, 200, "dynamic") --pone el cuerpo en el mundo y lo hace dinámico, por eso puede moverse
objects.bola1.shape = love.physics.newCircleShape(20) --la forma de la bola tiene un radio de 20
objects.bola1.fixture = love.physics.newFixture(objects.bola1.body, objects.bola1.shape, 2) --fija la forma al cuerpo y le da una densidad de 2.
objects.bola1.fixture:setRestitution(0.8) --deja que la pelota rebote
objects.bola2 = {}
objects.bola2.body = love.physics.newBody(world, 625, 200, "dynamic") --pone el cuerpo en el mundo y lo hace dinámico, por eso puede moverse
objects.bola2.shape = love.physics.newCircleShape(20) --la forma de la bola tiene un radio de 20
objects.bola2.fixture = love.physics.newFixture(objects.bola2.body, objects.bola2.shape, 2) --fija la forma al cuerpo y le da una densidad de 2.
objects.bola2.fixture:setRestitution(0.8) --deja que la pelota rebote
--crear dos bloques que harán de brazos de los péndulos
objects.barra1 = {}
objects.barra1.body = love.physics.newBody(world, 475, 200, "dynamic")
objects.barra1.shape = love.physics.newRectangleShape(0, 0, 100, 10)
objects.barra1.fixture = love.physics.newFixture(objects.barra1.body, objects.barra1.shape, 1) -- Una densidad mayor proporciona más masa.
objects.barra1.fixture:setRestitution(0.7)
objects.barra2 = {}
objects.barra2.body = love.physics.newBody(world, 595, 200, "dynamic")
objects.barra2.shape = love.physics.newRectangleShape(0, 0, 100, 10)
objects.barra2.fixture = love.physics.newFixture(objects.barra2.body, objects.barra2.shape, 1)
objects.barra2.fixture:setRestitution(0.7)
--poner el fondo
love.graphics.setBackgroundColor(111, 143, 255) --el color de fondo es un azul marica-ilusión
--uniones entre objetos
love.physics.newRevoluteJoint(objects.clavo.body, objects.barra1.body, 425, 200, false) --unión rotativa entre el clavo y una barra
love.physics.newWeldJoint(objects.barra1.body, objects.bola1.body, 520, 200) --unión fija entre una barra y su bola
love.physics.newRevoluteJoint(objects.bola1.body, objects.barra2.body, 530, 200, false) --unión rotativa entre la bola anterior y la barra
love.physics.newWeldJoint(objects.barra2.body, objects.bola2.body, 635, 200) --unión fija entre una barra y su bola
end
function love.quit()
print("La demostración ha finalizado.")
return false
end
function love.update(dt)
world:update(dt) --esto pone el mundo en movimiento
--controlar algunos eventos del teclado
if love.keyboard.isDown("right") then --pulsar la flecha derecha empuja la bola central a la derecha
objects.bola1.body:applyForce(800, 0)
elseif love.keyboard.isDown("left") then --pulsar la flecha izquierda empuja la bola central a la izquierda
objects.bola1.body:applyForce(-800, 0)
elseif love.keyboard.isDown("up") then --pulsar la flecha arriba pone la bola central en su posición de inicio, aunque con la inercia que lleve
objects.bola1.body:setPosition(525, 200)
elseif love.keyboard.isDown("escape") then
love.event.push("quit")
end
end
function love.draw()
love.graphics.setColor(50, 50, 50) --pone el color gris para los bloques
love.graphics.polygon("fill", objects.barra1.body:getWorldPoints(objects.barra1.shape:getPoints()))
love.graphics.polygon("fill", objects.barra2.body:getWorldPoints(objects.barra2.shape:getPoints()))
love.graphics.setColor(193, 47, 14) --pone un color rojo para la bola y el clavo
love.graphics.circle("fill", objects.bola1.body:getX(), objects.bola1.body:getY(), objects.bola1.shape:getRadius())
love.graphics.circle("fill", objects.bola2.body:getX(), objects.bola2.body:getY(), objects.bola2.shape:getRadius())
love.graphics.polygon("fill", objects.clavo.body:getWorldPoints(objects.clavo.shape:getPoints()))
love.graphics.setColor(250, 200, 0)
love.graphics.print('[esc] sale de la demo', 40, 15)
love.graphics.print('[-->] empuja la bola a la derecha.', 40, 30)
love.graphics.print('[<--] empuja la bola a la izquierda.', 40, 45)
love.graphics.print('[ ^ ] pone la bola en la posición de partida, aunque con la inercia que tenga en ese momento.', 40, 60)
love.graphics.print('Prueba de distribución cruzada -- Notxor', 40, 560)
end
Hay que destacar que las funciones love.load()
, love.draw()
y
love.update()
son centrales en el game engine para establecer y
controlar todos los parámetros que afectan al juego. Digamos que son
los mínimos que debe cumplir una demo en Löve 2D.
El funcionamiento
El funcionamiento es muy suave, tanto en el ordenador como en la tablet. Siendo una demo tan simple tampoco sobrecarga el sistema demasiado, supongo que en juegos complejos la cosa pueda cambiar.
En la imagen anterior se puede ver cómo se ve en mi portátil el ejemplo funcionando. En la siguiente se puede ver funcionando en la tablet bq M10 que tengo también con android.
Sin hacer esfuerzos estéticos, evidentemente, la adaptación a la pantalla de la tablet android queda un desplazada hacia arriba y a la izquierda. Pero supongo que con un poco más de código se podría capturar la resolución de la pantalla y centrar la demo.
La interacción también es complicada, no aparece el teclado virtual y
he tenido que conectar uno bluetooth para poder controlar la
demo. No sé si sería posible el acceder con Lua a los acelerómetros
y demás sensores del aparato, eso lo tendré que investigar en
adelante. Si continúo con estas investigaciones ya habrá noticias por
aquí. Otro de los puntos sería si se puede hacer una compilación del
fichero .love
con el .apk
de android para distribuir el juego o
la demo directamente.
De momento, lo dejo aquí, que no deja de ser una pequeña demo funcionando en android... pero hay temas que investigar.