Fondamentalmente si tratta di realizzare una funzione loop che esegue i calcoli della nuova posizione, in funzione del tempo passato, pulisce e ridisegna gli elementi, ed infine richiama se stessa tramite la funzione di sistema requestAnimationFrame
JavaScript
/* gestione ciclo di animazione */
let lastTime = new Date();
function loop() {
//calcolo il tempo passato tra un render e l'altro
const current = new Date();
const elapsed = current - lastTime; //circa 16 msec
updatePosition(elapsed);
render();
lastTime = current;
requestAnimationFrame(loop);
}
Tipicamente la funzione requestAnimationFrame viene richiamata ogni 16 millisecondi.
Trigonometria
Trattandosi di una animazione di un solido in rotazione, per calcolare la posizione dei vertici bisogna fare uso di un po' di trigonometria di base. In particolare le funzioni seno e coseno. Queste due funzioni, dato l'angolo, ritornano:
seno la proiezione del raggio di lunghezza 1 sull'asse delle Y
coseno la proiezione del raggio di lunghezza 1 sull'asse delle X
L'immagine seguente può chiarire il concetto
seno e coseno
Render e calcoli
Dato un raggio di lunghezza radius, che corrisponde al cerchio in cui sarà inscritto il poligono, un angolo di rotazione angle espresso in radianti e le coordinate del centro del cerchio cx e cy, si possono ricavare le coordinate x e y
JavaScript
// angolo giro
var PI_360 = Math.PI * 2;
var segment = 3; // triangolo
var angle= PI_360 / segment;
var radius=15;
var x = cx + Math.cos(angle) * radius;
var y = cy + Math.sin(angle) * radius;
In questo caso ho ricavato solo il primo vertice di un triangolo (segment = 3).
Per ricavare gli altri vertici dobbiamo introdurre altre variabili. Oltre all'angolo (segmentAngleInc) ricavato in base al numero dei lati compresi in un angolo giro, serve anche l'attuale angolo di rotazione ed un ciclo per ricavare tutti i vertici
JavaScript
var PI_360 = Math.PI * 2;
var segment = 3; // triangolo
var segmentAngleInc = PI_360 / segment;
var angleOffset = 0; // posizione iniziale dell'animazione
function render() {
var cx = canvas.width / 2;
var cy = canvas.height / 2;
var radius = cy - 10;
var segmentAngleInc = PI_360 / segment;
var angle = angleOffset;
// disegno i segmenti del poligono
for (let i = 0; i < segment; i++) {
var x = cx + Math.cos(angle) * radius;
var y = cy + Math.sin(angle) * radius;
/* todo: gestire disegno dei segmenti */
angle += segmentAngleInc;
}
}
Animazione
Trattandosi di un animazione semplice, la funzione updatePosition dovrà solo incrementare l'angolo di rotazione in funzione del tempo passato. Va però introdotto un nuovo concetto, ovvero la velocità di rotazione (animationSpeedAngle )
JavaScript
var animationSpeedAngle = (Math.PI / 180) * 45; // rotazione in gradi che dovrà compiere il solido in un secondo
function updatePosition(elapsed) {
if (elapsed === 0) {
elapsed = 16;
}
angleOffset += animationSpeedAngle * elapsed / 1000;
if (angleOffset >= PI_360) {
// se supero i 360 gradi riparto da 0
angleOffset = angleOffset % PI_360;
}
}