Antes de empezar, conoceremos la función "contains", que verifica si un rectángulo contiene otro rectángulo:
Rectangle.prototype.contains = function (rect) {
if (rect !== undefined) {
return (this.x < rect.x &&
this.x + this.width > rect.x + rect.width &&
this.y < rect.y &&
this.y + this.height > rect.y + rect.height);
}
};
Como podrás darte cuenta, esta función es bastante similar a la función "intersects", pero compara los mismos lados en lugar de los opuestos, y solo retorna verdadero en caso que el rectángulo recibido esté completamente dentro del rectángulo que lo evalúa, por lo que resulta poco usable en la mayoría de los casos de juegos. Es por ello que no habíamos visto esta función antes.Sin embargo, con los ajustes necesarios, de forma similar a como hicimos anteriormente a la función "distance" en los círculos, si creamos ancho y alto predefinido al objeto que recibimos en caso de no tenerlos, podemos evaluar también si el rectángulo contiene un punto de coordenadas:
Rectangle.prototype.contains = function (rect) {
if (rect !== undefined) {
var rectWidth = rect.width || 0,
rectHeight = rect.height || 0;
return (this.x < rect.x &&
this.x + this.width > rect.x + rectWidth &&
this.y < rect.y &&
this.y + this.height > rect.y + rectHeight);
}
};
Para probar que el código funciona correctamente, utilizaremos el mismo código que creamos de arrastrar y soltar círculos, reemplazando en esta ocasión los círculos por rectángulos: for (i = 0; i < 5; i += 1) {
draggables.push(new Rectangle(random(canvas.width), random(canvas.height), 20, 20));
}
Y evaluamos la interacción entre el arrastrable y el puntero al presionar el ratón: if (draggables[i].contains(pointer)) {
Al probar nuestro código de nuevo, podremos usar con éxito el arrastrar y soltar rectángulos. Notarás que al arrastrar un objeto, este no se ubica al centro respecto al cursor, si no a la esquina superior izquierda. Esto se puede corregir fácilmente sumando la mitad del alto y el ancho del rectángulo al asignar su nueva posición, pero en la siguiente entrega, haremos cambios que simplificarán mucho tareas como esta.La interacción entre rectángulos y el ratón es importante en los juegos, además de evaluar casos de interacción dentro de un juego, para crear también botones interactivos en las pantallas del mismo.
Código final:
/*jslint bitwise: true, es5: true */
(function (window, undefined) {
'use strict';
var canvas = null,
ctx = null,
lastPress = null,
lastRelease = null,
mouse = {x: 0, y: 0},
pointer = {x: 0, y: 0},
dragging = null,
draggables = [],
i = 0,
l = 0;
function Rectangle(x, y, width, height) {
this.x = (x === undefined) ? 0 : x;
this.y = (y === undefined) ? 0 : y;
this.width = (width === undefined) ? 0 : width;
this.height = (height === undefined) ? this.width : height;
}
Rectangle.prototype.contains = function (rect) {
if (rect !== undefined) {
var rectWidth = rect.width || 0,
rectHeight = rect.height || 0;
return (this.x < rect.x &&
this.x + this.width > rect.x + rectWidth &&
this.y < rect.y &&
this.y + this.height > rect.y + rectHeight);
}
};
Rectangle.prototype.intersects = function (rect) {
if (rect !== undefined) {
return (this.x < rect.x + rect.width &&
this.x + this.width > rect.x &&
this.y < rect.y + rect.height &&
this.y + this.height > rect.y);
}
};
Rectangle.prototype.fill = function (ctx) {
if (ctx !== undefined) {
ctx.fillRect(this.x, this.y, this.width, this.height);
}
};
function enableInputs() {
document.addEventListener('mousemove', function (evt) {
mouse.x = evt.pageX - canvas.offsetLeft;
mouse.y = evt.pageY - canvas.offsetTop;
}, false);
document.addEventListener('mouseup', function (evt) {
lastRelease = evt.which;
}, false);
canvas.addEventListener('mousedown', function (evt) {
evt.preventDefault();
lastPress = evt.which;
}, false);
canvas.addEventListener('touchmove', function (evt) {
evt.preventDefault();
var t = evt.targetTouches;
mouse.x = t[0].pageX - canvas.offsetLeft;
mouse.y = t[0].pageY - canvas.offsetTop;
}, false);
canvas.addEventListener('touchstart', function (evt) {
evt.preventDefault();
lastPress = 1;
var t = evt.targetTouches;
mouse.x = t[0].pageX - canvas.offsetLeft;
mouse.y = t[0].pageY - canvas.offsetTop;
}, false);
canvas.addEventListener('touchend', function (evt) {
lastRelease = 1;
}, false);
canvas.addEventListener('touchcancel', function (evt) {
lastRelease = 1;
}, false);
}
function random(max) {
return ~~(Math.random() * max);
}
function paint(ctx) {
// Clean canvas
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw rectangles
ctx.fillStyle = '#00f';
for (i = 0, l = draggables.length; i < l; i += 1) {
draggables[i].fill(ctx);
}
// Debug pointer position
ctx.fillStyle = '#0f0';
ctx.fillRect(pointer.x - 1, pointer.y - 1, 2, 2);
// Debug dragging rectangle
ctx.fillStyle = '#fff';
ctx.fillText('Dragging: ' + dragging, 0, 10);
}
function act() {
// Set pointer to mouse
pointer.x = mouse.x;
pointer.y = mouse.y;
// Limit pointer into canvas
if (pointer.x < 0) {
pointer.x = 0;
}
if (pointer.x > canvas.width) {
pointer.x = canvas.width;
}
if (pointer.y < 0) {
pointer.y = 0;
}
if (pointer.y > canvas.height) {
pointer.y = canvas.height;
}
if (lastPress === 1) {
// Check for current dragging rectangle
for (i = 0, l = draggables.length; i < l; i += 1) {
if (draggables[i].contains(pointer)) {
dragging = i;
break;
}
}
} else if (lastRelease === 1) {
// Release current dragging rectangle
dragging = null;
}
// Move current dragging rectangle
if (dragging !== null) {
draggables[dragging].x = pointer.x;
draggables[dragging].y = pointer.y;
}
}
function run() {
window.requestAnimationFrame(run);
act();
paint(ctx);
lastPress = null;
lastRelease = null;
}
function init() {
// Get canvas and context
canvas = document.getElementById('canvas');
ctx = canvas.getContext('2d');
canvas.width = 200;
canvas.height = 300;
// Create draggables
for (i = 0; i < 5; i += 1) {
draggables.push(new Rectangle(random(canvas.width), random(canvas.height), 20, 20));
}
// Start game
enableInputs();
run();
}
window.addEventListener('load', init, false);
}(window));
No hay comentarios.:
Publicar un comentario