OK, ho tutto funzionato, ci ho messo un'eternità, quindi pubblicherò la mia soluzione dettagliata qui.
Nota: tutti gli esempi di codice sono in JavaScript.
Quindi suddividiamo il problema nelle parti di base:
È necessario calcolare la lunghezza di, nonché i punti tra 0..1sulla curva di Bezier
Ora devi regolare il ridimensionamento del tuo Tper accelerare la nave da una velocità all'altra
Ottenere il Bezier giusto
Trovare un po 'di codice per disegnare una curva di Bezier è facile, tuttavia ci sono molti approcci diversi, uno di questi è l' algoritmo DeCasteljau , ma puoi anche usare l' equazione per le curve cubiche di Bézier:
// Part of a class, a, b, c, d are the four control points of the curve
x: function (t) {
return ((1 - t) * (1 - t) * (1 - t)) * this.a.x
+ 3 * ((1 - t) * (1 - t)) * t * this.b.x
+ 3 * (1 - t) * (t * t) * this.c.x
+ (t * t * t) * this.d.x;
},
y: function (t) {
return ((1 - t) * (1 - t) * (1 - t)) * this.a.y
+ 3 * ((1 - t) * (1 - t)) * t * this.b.y
+ 3 * (1 - t) * (t * t) * this.c.y
+ (t * t * t) * this.d.y;
}
Con questo, ora si può disegnare una curva più bezier chiamando xe ycon tquali intervalli da 0 to 1, diamo un'occhiata:

Uh ... non è proprio una distribuzione uniforme dei punti, vero?
A causa della natura della curva di Bézier, i punti su 0...1hanno diversi arc lenghts, quindi i segmenti vicino all'inizio e alla fine sono più lunghi di quelli che si trovano vicino al centro della curva.
Mappatura T uniformemente sulla parametrizzazione della lunghezza dell'arco AKA della curva
Quindi che si fa? Bene in termini semplici abbiamo bisogno di una funzione per mappare il nostro Tsul tdella curva, in modo che i nostri T 0.25risultati nella tquella a 25%della lunghezza della curva.
Come lo facciamo? Bene, noi Google ... ma si scopre che il termine non è così googleable , e ad un certo punto colpirai questo PDF . Il che è sicuramente un'ottima lettura, ma nel caso in cui hai già dimenticato tutte le cose matematiche che hai imparato a scuola (o semplicemente non ti piacciono quei simboli matematici) è piuttosto inutile.
E adesso? Bene, andate ancora su Google (leggete: 6 ore) e finalmente trovate un ottimo articolo sull'argomento (incluse belle foto! ^ _ ^ "):
Http://www.planetclegg.com/projects/WarpingTextToSplines.html
Fare il codice attuale
Nel caso in cui non potessi resistere al download di quel PDF, anche se hai già perso le tue conoscenze matematiche molto, molto, molto tempo fa (e sei riuscito a saltare l' ottimo link dell'articolo), potresti ora pensare: "Dio, ci vorrà centinaia di righe di codice e tonnellate di CPU "
No, non lo farà. Perché facciamo ciò che fanno tutti i programmatori, quando si tratta di cose matematiche:
semplicemente imbrogliamo.
Parametrizzazione della lunghezza dell'arco, il modo pigro
Ammettiamolo, non abbiamo bisogno di una precisione infinita nel nostro gioco, vero? Quindi, a meno che tu non stia lavorando alla Nasa e non preveda di inviare persone su Marte, non avrai bisogno di una 0.000001 pixelsoluzione perfetta.
Quindi, come possiamo mappare Tsu t? È semplice e comprende solo 3 passaggi:
Calcola i Npunti sulla curva usando te archivia arc-length(ovvero la lunghezza della curva) in quella posizione in un array
Per mappare Tsu t, prima moltiplica Tper la lunghezza totale della curva per ottenere, uquindi cerca nell'array di lunghezze l'indice del valore più grande che è più piccolo diu
Se abbiamo avuto un risultato esatto, restituiamo il valore di matrice in quell'indice diviso per N, se non interpolare un po 'tra il punto che abbiamo trovato e quello successivo, dividere nuovamente la cosa per Ne restituire.
È tutto! Quindi ora diamo un'occhiata al codice completo:
function Bezier(a, b, c, d) {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
this.len = 100;
this.arcLengths = new Array(this.len + 1);
this.arcLengths[0] = 0;
var ox = this.x(0), oy = this.y(0), clen = 0;
for(var i = 1; i <= this.len; i += 1) {
var x = this.x(i * 0.05), y = this.y(i * 0.05);
var dx = ox - x, dy = oy - y;
clen += Math.sqrt(dx * dx + dy * dy);
this.arcLengths[i] = clen;
ox = x, oy = y;
}
this.length = clen;
}
Questo inizializza la nostra nuova curva e calcola la arg-lenghts, memorizza anche l'ultima delle lunghezze come total lengthla curva, il fattore chiave qui è this.lenquale è la nostra N. Più è alta, più precisa sarà la mappatura, poiché una curva delle dimensioni nell'immagine sopra 100 pointssembra essere sufficiente, se hai solo bisogno di una buona stima della lunghezza, qualcosa come 25farebbe già il lavoro con solo 1 pixel di sconto nel nostro esempio, ma avrai una mappatura meno precisa che comporterà una distribuzione non uniforme di Tquando mappata t.
Bezier.prototype = {
map: function(u) {
var targetLength = u * this.arcLengths[this.len];
var low = 0, high = this.len, index = 0;
while (low < high) {
index = low + (((high - low) / 2) | 0);
if (this.arcLengths[index] < targetLength) {
low = index + 1;
} else {
high = index;
}
}
if (this.arcLengths[index] > targetLength) {
index--;
}
var lengthBefore = this.arcLengths[index];
if (lengthBefore === targetLength) {
return index / this.len;
} else {
return (index + (targetLength - lengthBefore) / (this.arcLengths[index + 1] - lengthBefore)) / this.len;
}
},
mx: function (u) {
return this.x(this.map(u));
},
my: function (u) {
return this.y(this.map(u));
},
Il codice di mappatura effettivo, prima facciamo un semplice binary searchsulle nostre lunghezze memorizzate per trovare la lunghezza più grande che è più piccola targetLength, quindi restituiamo o facciamo l'interpolazione e restituiamo.
x: function (t) {
return ((1 - t) * (1 - t) * (1 - t)) * this.a.x
+ 3 * ((1 - t) * (1 - t)) * t * this.b.x
+ 3 * (1 - t) * (t * t) * this.c.x
+ (t * t * t) * this.d.x;
},
y: function (t) {
return ((1 - t) * (1 - t) * (1 - t)) * this.a.y
+ 3 * ((1 - t) * (1 - t)) * t * this.b.y
+ 3 * (1 - t) * (t * t) * this.c.y
+ (t * t * t) * this.d.y;
}
};
Ancora una volta questo calcola tsulla curva.
Tempo per i risultati

Ormai usando mxe myottieni una distribuzione uniforme Tsulla curva :)
Non è stato difficile, vero? Ancora una volta, si scopre che una soluzione semplice (anche se non perfetta) sarà sufficiente per un gioco.
Se vuoi vedere il codice completo, c'è un Gist disponibile:
https://gist.github.com/670236
Infine, accelerando le navi
Quindi tutto ciò che rimane ora è accelerare le navi lungo il loro percorso, mappando la posizione su Tcui poi utilizziamo per trovare la tcurva.
Per prima cosa abbiamo bisogno di due delle equazioni del moto , vale a dire ut + 1/2at²e(v - u) / t
Nel codice effettivo sarebbe simile al seguente:
startSpeed = getStartingSpeedInPixels() // Note: pixels
endSpeed = getFinalSpeedInPixels() // Note: pixels
acceleration = (endSpeed - startSpeed) // since we scale to 0...1 we can leave out the division by 1 here
position = 0.5 * acceleration * t * t + startSpeed * t;
Quindi lo ridimensioniamo 0...1facendo:
maxPosition = 0.5 * acceleration + startSpeed;
newT = 1 / maxPosition * position;
Ed ecco qua, le navi ora si muovono senza intoppi lungo il percorso.
Nel caso in cui non funzioni ...
Quando stai leggendo questo, tutto funziona benissimo e dandy, ma inizialmente ho avuto alcuni problemi con la parte dell'accelerazione, quando ho spiegato il problema a qualcuno nella chat di Gamedev ho trovato l'ultimo errore nel mio pensiero.
Nel caso in cui non ti sia già dimenticato dell'immagine nella domanda originale, menziono slì, risulta che sè la velocità in gradi , ma le navi si muovono lungo il percorso in pixel e mi ero dimenticato di questo fatto. Quindi quello che dovevo fare in questo caso era convertire lo spostamento in gradi in uno spostamento in pixel, risulta che questo è piuttosto facile:
function rotationToMovement(planetSize, rotationSpeed) {
var r = shipAngle * Math.PI / 180;
var rr = (shipAngle + rotationSpeed) * Math.PI / 180;
var orbit = planetSize + shipOrbit;
var dx = Math.cos(r) * orbit - Math.cos(rr) * orbit;
var dy = Math.sin(r) * orbit - Math.sin(rr) * orbit;
return Math.sqrt(dx * dx + dy * dy);
};
Quindi e questo è tutto! Grazie per aver letto ;)