Archivo de la categoría: HTML5

Matemáticas, física y animación con Canvas html5 – parte 2

canvas
Estimados! Disculpen por dejar tanto tiempo el blog botado, ahora continuaré con los ejercicios de canvas. Este post es la continuación de Matemáticas, física y animación con Canvas html5 – parte 1. Para esta ocación no profundizaré tanto en puntos matemáticos como lo hice en la primera parte, por lo que recomiendo que si no la han leído lo hagan y luego continuen con esta.
Para este ejercicio vamos a crear muchas pelotas chocando con las paredes (no entre si) y moviendose a diferentes velocidades según el tamaño de cada una.
Si quieren ver el resultado bajen al final de este post
Al igual que el post anterior, comenzaré pegando todo el código para que lo vean y luego explicando cada uno de los puntos relevantes.
Comenzamos importando nuestra librería modernizr entre las etiquetas “head” de nuestro HTML para garantizar la compatibilidad de nuestro canvas con todos los navegadores.

<script src="http://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.1/modernizr.min.js"></script>

y dentro de nuestras etiquetas body creamos el canvas donde se dibujará nuestro script.

<div>
	<canvas id="canvasTwo" width="600" height="300"> 
		Cambiate de navegador!
	</canvas>
</div>

Ahora el código completo de nuestro javascript

[javascript]
window.addEventListener(‘load’, eventWindowLoaded, false);
function eventWindowLoaded(){
canvasAppPartTwo();
}
function canvasSupport(){
return Modernizr.canvas;
}
function canvasAppPartTwo(){
if(!canvasSupport()){
return;
}

function drawScreen(){
context.fillStyle = ‘#EEEEEE’;
context.fillRect(0, 0, theCanvas.width, theCanvas.height);
context.strokeStyle = ‘#000000’;
context.strokeRect(1, 1, theCanvas.width-2, theCanvas.height-2);

var ball;
for(var i = 0; i < balls.length; i++){
ball = balls[i];
context.fillStyle = ball.color;
ball.x += ball.xunits;
ball.y += ball.yunits;

context.beginPath();
context.arc(ball.x, ball.y, ball.radius, 0, Math.PI*2, true);
context.closePath();
context.fill();

if((ball.x+ball.radius) > theCanvas.width || ball.x < 0){
ball.angle = 180 – ball.angle;
updateBall(ball);
}else if((ball.y+ball.radius) > theCanvas.height || ball.y < 0){
ball.angle = 360 – ball.angle;
updateBall(ball);
}
}
}
function updateBall(ball){
ball.radians = ball.angle * Math.PI/ 180;
ball.xunits = Math.cos(ball.radians) * ball.speed;
ball.yunits = Math.sin(ball.radians) * ball.speed;
}

var numBalls = 1000;
var maxSize = 8;
var minSize = 5;
var maxSpeed = maxSize + 5;
var balls = new Array();
var tempBall;
var tempX;
var tempY;
var tempSpeed;
var tempAngle;
var tempRadius;
var tempRadians;
var tempXunits;
var tempYunits;
var tempColor;

theCanvas = document.getElementById(‘canvasTwo’);
context = theCanvas.getContext(‘2d’);

for(var i = 0; i < numBalls; i++){
tempRadius = Math.floor(Math.random()*maxSize)+minSize;
tempX = tempRadius*2 + (Math.floor(Math.random()*theCanvas.width)-tempRadius*2);
tempY = tempRadius*2 + (Math.floor(Math.random()*theCanvas.height)-tempRadius*2);
tempSpeed = maxSpeed-tempRadius;
tempAngle = Math.floor(Math.random()*360);
tempRadians = tempAngle * Math.PI/ 180;
tempXunits = Math.cos(tempRadians) * tempSpeed;
tempYunits = Math.sin(tempRadians) * tempSpeed;
tempColor = ‘#’+Math.floor(Math.random()*16777215).toString(16);
tempBall = {
x: tempX,
y: tempY,
radius: tempRadius,
speed: tempSpeed,
angle: tempAngle,
xunits: tempXunits,
yunits: tempYunits,
color: tempColor
}
balls.push(tempBall);
}
setInterval(drawScreen, 33);
}

[/javascript]

Ahora explicaré las cambios. Los primero es determinar la función que se ejecutará al momento que se cargue el javascript.

[javascript]
window.addEventListener(‘load’, eventWindowLoaded, false);
function eventWindowLoaded(){
canvasAppPartTwo();
}
[/javascript]

Definimos un intervalo para ir ejecutando el canvas.

[javascript]
setInterval(drawScreen, 33);
[/javascript]

Entonces en orden de ejecución debemos definir las variables que utilizares. Solo comentaré las nuevas que agregé a este ejemplo. Las demás son variables que utilizaremos de forma temporal.

[javascript]
var numBalls = 1000; // Numero de bolas
var maxSize = 8; // Tamaño máximo que pueden tener
var minSize = 5; // Tamaño minimo
var maxSpeed = maxSize + 5; // Velocidad máxima
var balls = new Array(); // Arreglo que contendrá las bolas que creemos.
[/javascript]

Rerefenciamos el canvas en el contexto de nuestro script

[javascript]
theCanvas = document.getElementById(‘canvasTwo’);
context = theCanvas.getContext(‘2d’);
[/javascript]

Lo siguiente es hacer un “for” que recorrerá para crear cada una de las pelotas, para este ejemplo serán 1000 (pueden poner el número que quieran, solo sean considerados con su máquina).

[javascript]
for(var i = 0; i < numBalls; i++){

}
[/javascript]

Con esto vamos creando lo valores temprales de nuestras bolas. No me detendré en este punto porque ya está explicado en el primero post como voy sacando los cálculos, la única diferencia es que voy jugando con valores random.
Así encontes calculamos el radio entre el tamaño minimo que determinamos y el máximo.

[javascript]
tempRadius = Math.floor(Math.random()*maxSize)+minSize;
[/javascript]

Luego calculamos la posición de la bola dentro del canvas, el valor random es el tamaño del canvas menos su radio al cuadrado.

[javascript]
tempX = tempRadius*2 + (Math.floor(Math.random()*theCanvas.width)-tempRadius*2);
tempY = tempRadius*2 + (Math.floor(Math.random()*theCanvas.height)-tempRadius*2);
[/javascript]

La velocidad que está directamente relacionada con el tamaño de la bola, ya que mientras más grande sea, más lento debe moverse.

[javascript]
tempSpeed = maxSpeed-tempRadius;
[/javascript]

Y los cambios de angulos en la dirección de nuestra bola.

[javascript]
tempAngle = Math.floor(Math.random()*360);
tempRadians = tempAngle * Math.PI/ 180;
tempXunits = Math.cos(tempRadians) * tempSpeed;
tempYunits = Math.sin(tempRadians) * tempSpeed;
[/javascript]

FinaLmente le damos un color random a la pelota para poder diferenciarlas unas de otras.

[javascript]
tempColor = ‘#’+Math.floor(Math.random()*16777215).toString(16);
[/javascript]

Ya teniendo todos los valores, agregamos la pelota a nuestro arreglo de bolas.

[javascript]
tempBall = {
x: tempX,
y: tempY,
radius: tempRadius,
speed: tempSpeed,
angle: tempAngle,
xunits: tempXunits,
yunits: tempYunits,
color: tempColor
}
balls.push(tempBall);
[/javascript]

Ya dentro de la función drawScreen dibujamos el contenedor de nuestro canvas.

[javascript]
context.fillStyle = ‘#EEEEEE’;
context.fillRect(0, 0, theCanvas.width, theCanvas.height);
context.strokeStyle = ‘#000000’;
context.strokeRect(1, 1, theCanvas.width-2, theCanvas.height-2);
[/javascript]

Y volvemos a recorrer el arreglo de bolas para id dibujandolas dentro de nuestro canvas. Utilizaré la variable auxiliar ball donde iré referenciando cada bola.

[javascript]
var ball;
for(var i = 0; i < balls.length; i++){

}
[/javascript]

Referenciamos los valores.

[javascript]
ball = balls[i];
ball.x += ball.xunits;
ball.y += ball.yunits;
[/javascript]

Y dibujamos la bola con su respectivo color y tamaño.

[javascript]
context.fillStyle = ball.color;
context.beginPath();
context.arc(ball.x, ball.y, ball.radius, 0, Math.PI*2, true);
context.closePath();
context.fill();
[/javascript]

Ahora capturo el momento en donde la bola debe cambiar su dirección para no salir del canvas. Llamando a la función updateBall.

[javascript]
if((ball.x+ball.radius) > theCanvas.width || ball.x < 0){
ball.angle = 180 – ball.angle;
updateBall(ball);
}else if((ball.y+ball.radius) > theCanvas.height || ball.y < 0){
ball.angle = 360 – ball.angle;
updateBall(ball);
}
[/javascript]

Al comienzo del for definimos una variable auxiliar que ahora utilizamos para poder actualizar la bola fuera del for.

[javascript]
function updateBall(ball){
ball.radians = ball.angle * Math.PI/ 180;
ball.xunits = Math.cos(ball.radians) * ball.speed;
ball.yunits = Math.sin(ball.radians) * ball.speed;
}
[/javascript]

Y por fin el resultado final! Hay varias cosas que podemos mejorar, como por ejemplo que las pelotas choquen entre ellas. Haré una tercera parte para eso.
Gracias por su tiempo y por espero que el tutorial les haya gustado.

Actualiza tu browser por la chucha!

Canvas y WebGL usando Three.js

canvas
Siguiendo con los post de Canvas. Les mostraré un pequeño ejemplo de la utilización de Three.js, una librería de Canvas y WebGL muy sencilla de implementar.
Lo primero como siempre es importarla entre nuestras etiquetas head de nuestro html.
http://ajax.googleapis.com/ajax/libs/threejs/r67/three.min.js
Y creamos un div dentro de las etiquetas body del html con el id basicMoveWithThree donde se creará nuestro canvas. Además yo le especifiqué un ancho y un alto: style=”width: 600px; height: 400px;”.
Pegaré todo el código de este ejemplo y luego lo explicaré. Lo que haremos será crear un cubo con WebGL el cuál rotará sobre su mismo eje. Este es un ejemplo bastante sencillo, la idea es solo mostrar lo fácil que es utilizar esta librería.
[javascript]
window.addEventListener(‘load’, eventWindowLoaded, false);
function eventWindowLoaded(){
basicMoveWithThree();
}
function basicMoveWithThree(){
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(25, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.z = 5;

var renderer = new THREE.WebGLRenderer();
renderer.setSize(600, 400);
renderer.setClearColor(‘#f7f7f7’, 1);
document.getElementById(‘basicMoveWithThree’).appendChild(renderer.domElement);

var geometry = new THREE.BoxGeometry(1,1,1);
var material = new THREE.MeshLambertMaterial({color: ‘blue’});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);

var ambientLight = new THREE.AmbientLight(0x000044);
scene.add(ambientLight);

var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 1, 1).normalize();
scene.add(directionalLight);

var angularSpeed = 0.2;
var lastTime = 0;
var render = function(){
var time = (new Date()).getTime();
var timeDiff = time – lastTime;
var angleChange = angularSpeed * timeDiff * 2 * Math.PI / 1000;
cube.rotation.x += angleChange;
cube.rotation.y += angleChange;
lastTime = time;
renderer.render(scene, camera);
requestAnimationFrame(render);
};

render();
}
[/javascript]
En la primera parte del código cargo la función que contendrá mi script (esto es rutinario de javascript) y llamo a la función basicMoveWithThree declarada más abajo.
[javascript]
window.addEventListener(‘load’, eventWindowLoaded, false);
function eventWindowLoaded(){
basicMoveWithThree();
}
[/javascript]
Ahora ya la parte entretenida. Lo primero que debo hacer es crear una Escena donde si visualizará mi WebGL y es a esta donde se cargarán todos los elementos que vaya creando más adelante, y a su vez crear una cámara que será la perspectiva con la que veré la escena. Hay 3 tipos de cámaras: Camera, OrthographicCamera y PerspectiveCamera. Para este ejemplo usarémos la última, que recibe 4 parámetros:
– El campo de visión vertital de abajo hacia arriba en grados.
– Relación del aspecto del ancho dividido por la altura.
– Plano cercano.
– Plano lejano.
Y luego determino la posición de la cámara en grados.
[javascript]
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(25, window.innerWidth/window.innerHeight, 0.1, 1000);
camera.position.z = 5;
[/javascript]
El paso siguiente es determinar la forma en que se renderizará el Canvas o el WebGL (para este caso será con WebGL), el tamaño del canvas, el color de fondo, la profundidad, la sombra, la gama, etc.
Hay 4 formas de renderizar: CanvasRenderer, WebGLRenderer, WebGLRenderTarget y WebGLRenderTargetCube.
Pero para este caso usaremos WebGLRenderer, con un tamaño de 600 de ancho y 400 de alto, y usé el color de fondo de mi blog #f7f7f7 (por defecto es negro).
[javascript]
var renderer = new THREE.WebGLRenderer();
renderer.setSize(600, 400);
renderer.setClearColor(‘#f7f7f7’, 1);
[/javascript]
Junto a crear la forma de renderizar debo especificar donde lo aplicaré, en este caso será a un div con id ‘basicMoveWithThree’.
[javascript]
document.getElementById(‘basicMoveWithThree’).appendChild(renderer.domElement);
[/javascript]
Ahora crearemos el cubo. Debemos especificar el tipo de figura que usaremos, estas pueden ser figuras geométricas o curvas. Geométricas pueden ser: BoxGeometry, CircleGeometry, CubeGeometry, CylinderGeometry, ExtrudeGeometry, IcosahedronGeometry, LatheGeometry, OctahedronGeometry, ParametricGeometry, PlaneGeometry, PolyhedronGeometry, RingGeometry, ShapeGeometry, SphereGeometry, TetrahedronGeometry, TextGeometry, TorusGeometry, TorusKnotGeometry y TubeGeometry.
Y los tipos de curvas pueden ser: ArcCurve, ClosedSplineCurve3, CubicBezierCurve, CubicBezierCurve3, EllipseCurve, LineCurve, LineCurve3, QuadraticBezierCurve, QuadraticBezierCurve3, SplineCurve y SplineCurve3.
Y así ya podemos espeficiar el tipo de material (o superficie) del cuál estará compuesto nuestro cubo. Estos pueden ser: LineBasicMaterial, LineDashedMaterial, Material, MeshBasicMaterial, MeshDepthMaterial, MeshFaceMaterial, MeshLambertMaterial, MeshNormalMaterial, MeshPhongMaterial, PointCloudMaterial, RawShaderMaterial, ShaderMaterial, SpriteCanvasMaterial y SpriteMaterial.
Es importante elegir bien el tipo de material de nuestros objetos ya que esto influirá si aplicamos otros aspectos al escenario como la luz. Para este ejemplo usaré MeshLambertMaterial y le pasaré el color azul como parámetro, la clase MeshLambertMaterial puede recibir varios parámetros como intensidad de la luz o la refracción.
Luego creamos el elemento pasandole el elemento geométrico y el material del cuál estará compuesto, para luego agregarlo al escenario definido anteriormente con la función ‘add’.
[javascript]
var geometry = new THREE.BoxGeometry(1,1,1);
var material = new THREE.MeshLambertMaterial({color: ‘blue’});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
[/javascript]
También podemos trabajar con la luz y su dirección en el escenario. Los tipos de luz que podemos utilizar son: AmbientLight, AreaLight, DirectionalLight, HemisphereLight, Light, PointLight y SpotLight.
Para este ejemplo usaremos AmbientLight recibiendo como parámetro el color de la luz.
[javascript]
var ambientLight = new THREE.AmbientLight(0x000044);
scene.add(ambientLight);
[/javascript]
Y luego especificamos la dirección que tendrá la luz en la escena, también recibiendo el color de la luz.
[javascript]
var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 1, 1).normalize();
scene.add(directionalLight);
[/javascript]
El paso final es ejecutar la renderización, y especificar los movientos que queramos realizar sobre los objetos que agregamos a la escena. Podemos utilizar la diferencia del tiempo actual para controlar las revoluciones de rotación de los elementos (en mi caso del cubo). Y luego es importante ejecutar requestAnimationFrame(render); para que el Canvas o WebGL se aplique en forma de frames (se vuelva a llamar).
[javascript]
var angularSpeed = 0.2;
var lastTime = 0;
var render = function () {
var time = (new Date()).getTime();
var timeDiff = time – lastTime;
var angleChange = angularSpeed * timeDiff * 2 * Math.PI / 1000;
cube.rotation.x += angleChange;
cube.rotation.y += angleChange;
lastTime = time;
renderer.render(scene, camera);
requestAnimationFrame(render);
};
render();
[/javascript]
Y así finalmente nuestro WebGL se vería así!

Recuerden que pueden consultar toda la información de la librería en la página oficial y si tienen alguna observación o mejora del ejemplo no duden en comentarla. Saludos!

Matemáticas, física y animación con Canvas html5 – parte 1

canvas
Canvas es una de las cosas que encuentro más interesantes y entretenidas de HTML5, con ella podemos realizar desde gráficos, juegos y un sin fín de cosas sin necesidad de utitilizar ningún plugin en nuestro navegador. Para este ejemplo haremos una pelota (un punto grande) que rebote en contra una pared (caja).
Adjuntaré la librería de Modernizr para garantizar la compatividad en todos los navegadores. Agregando entre las etiquetas head el siguiente código.
<script src="http://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.1/modernizr.min.js"></script>

Comenzaré este post escribiendo todo el código para este ejemplo y luego iremos explicando paso a paso lo que tenemos que hacer. Al final del post está el canvas funcionando.
Pegamos el siguiente código en nuestro head entre las etiquetas script del documento html.
[javascript]
window.addEventListener(‘load’, eventWindowLoaded, false);
function eventWindowLoaded(){
canvasAppPartOne();
}
function canvasSupport(){
return Modernizr.canvas;
}
function canvasAppPartOne(){
if(!canvasSupport()){
return;
}

function drawScreen(){
context.fillStyle = ‘#EEEEEE’;
context.fillRect(0, 0, theCanvas.width, theCanvas.height);
context.strokeStyle = ‘#000000’;
context.strokeRect(1, 1, theCanvas.width-2, theCanvas.height-2);
ball.x += xunits;
ball.y += yunits;
if(ball.x+15 > theCanvas.width || ball.x < 15){
angle = 180 – angle;
updateBall();
}else if(ball.y+15 > theCanvas.height || ball.y < 15){
angle = 360 – angle;
updateBall();
}
context.fillStyle = ‘#000000’;
context.beginPath();
context.arc(ball.x, ball.y, 15, 0, Math.PI*2, true);
context.closePath();
context.fill();
}
function updateBall(){
radians = angle * Math.PI/ 180;
xunits = Math.cos(radians) * speed;
yunits = Math.sin(radians) * speed;
}

var speed = 10;
var angle = 35;
var radians = 0;
var p1 = {x:20,y:20};
var xunits = 0;
var yunits = 0;
var ball = {x:p1.x, y:p1.y};
updateBall();

theCanvas = document.getElementById(‘canvasOne’);
context = theCanvas.getContext(‘2d’);
setInterval(drawScreen, 33);
}
[/javascript]

Luego entre las etiquetas body de nuestro html colocamos el contenedor de nuestro canvas.

<canvas id="canvasOne" width="600" height="300">
  Please update you browser!
</canvas>

Ahora a explicar el código.
Lo primero que hacemos es cargar todo nuestro script en la función load de javascript, para que cuando se cargue la página también lo haga nuestro script.
[javascript]
window.addEventListener(‘load’, eventWindowLoaded, false);
function eventWindowLoaded(){
canvasAppPartOne();
}
[/javascript]

Definimos las variables iniciales de nuestro script. Usaremos la variable speed para determinar la velocidad inicial de la pelota, angle para el ángulo inicial con el cuál se moverá la pelota, radians porque nuestra pelota se moverá en forma de vector con dirección y sentido, y utilizaremos radiales para transformar desde el ángulo, ya que será más legible para nosotros, p1 es la posición inicial de la pelota en la caja, xunits y yunits contendrán la suma que debe aplicarse a la posición de nuestra pelota mientras rebote por la caja, y finalmente ball que será nuestra pelota.
[javascript]
var speed = 10;
var angle = 35;
var radians = 0;
var p1 = {x:20,y:20};
var xunits = 0;
var yunits = 0;
var ball = {x:p1.x, y:p1.y};
[/javascript]

Luego referenciamos el elemento DOM en nuestro html, determinamos que trabajaremos bajo un contexto 2d y definimos el intervalo de refresco de nuestro canvas en milisegundos.
[javascript]
theCanvas = document.getElementById(‘canvasOne’);
context = theCanvas.getContext(‘2d’);
setInterval(drawScreen, 33);
[/javascript]

La función drawScreen será la encargada de pintar el canvas por cada intervalo que hayamos definido. Lo primero que pintamos es la caja con un borde para poder ver los límites. Las primeras dos lineas pintan el fondo y las dos siguiente pintan el borde.
[javascript]
context.fillStyle = ‘#EEEEEE’;
context.fillRect(0, 0, theCanvas.width, theCanvas.height);
context.strokeStyle = ‘#000000’;
context.strokeRect(1, 1, theCanvas.width-2, theCanvas.height-2);
[/javascript]

Ahora con una condición if, vamos podemos saber cuando la pelota choca con los el eje x y el eje y, así podemos cambiar la dirección del vector. En la primera linea si choca con el eje x y en la cuarta linea si choca con el vector y. El número 15 que le sumo a la variable “ball” corresponde radio de la pelota, ya que de no ser así, el borde de la caja chocaría con el centro de la pelota. Fíjese que estoy utilizando la función updateBall(), esta la explicaré un poco más adelante.
[javascript]
if(ball.x+15 > theCanvas.width || ball.x < 15){
angle = 180 – angle;
updateBall();
}else if(ball.y+15 > theCanvas.height || ball.y < 15){
angle = 360 – angle;
updateBall();
}
[/javascript]

Seguidamente dibujamos nuestra pelota que se moverá (o eso parece) por nuestra caja.
[javascript]
context.fillStyle = ‘#000000’;
context.beginPath();
context.arc(ball.x, ball.y, 15, 0, Math.PI*2, true);
context.closePath();
context.fill();
[/javascript]

Y ahora fuera de nuestra función drawScreen, definimos la función updateBall. Que se encargará de transformar nuestro cambio en el angulo que hicimos en el if anterior a radiales, con lo que finalmente cambiará la dirección de la pelota.
[javascript]
function updateBall(){
radians = angle * Math.PI/ 180;
xunits = Math.cos(radians) * speed;
yunits = Math.sin(radians) * speed;
}
[/javascript]
Y aquí está el resultado.
Espero que les haya servido y si tienen suguerencias para mejorar el código puedes escribirlas!
Saludos!

Actualiza tu browser por la chucha!