Tamam, her şey çalışıyor, sonsuza dek sürdü, bu yüzden ayrıntılı çözümümü buraya göndereceğim.
Not: Tüm kod örnekleri JavaScript’tedir.
Öyleyse sorunu temel parçalara ayıralım:
0..1Bezier eğrisi arasındaki noktaların yanı sıra uzunluğunu da hesaplamanız gerekir.
Artık Tgemiyi bir hızdan diğerine hızlandırmak için ölçeklemenizi ayarlamanız gerekiyor.
Bezier'i Doğru Almak
Bezier eğrisi çizmek için bazı kodlar bulmak kolaydır, ancak bunlardan biri DeCasteljau Algoritması olmakla birlikte, birkaç farklı yaklaşım vardır , ancak aynı zamanda kübik Bézier eğrileri için de denklemi kullanabilirsiniz :
// 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;
}
Bununla, şimdi çağrı yaparak xve yaralarında thangi aralıklarla bir bezier eğrisi çizebileceğimize 0 to 1bakalım:

Uh ... bu gerçekten puanların eşit bir dağılımı değil, değil mi?
Bézier eğrisinin doğası gereği, noktalar 0...1farklıdır arc lenghts, bu nedenle başlangıç ve bitişe yakın bölümler, eğrinin ortasına yakın olanlardan daha uzundur.
AKA yay uzunluğu parametresi eğrisinde eşit olarak T eşlemesi
Peki ne yapmalı? Eh basit terimlerle Nerede biz eşlemek için bir işlev gerekir Tüzerine t, eğrinin böylece bizim T 0.25sonuçlanır tde en o 25%eğrisinin uzunluğu.
Bunu nasıl yaparız? Şey, biz Google ... ... ancak bu terimin bu kadar mantıklı olmadığı ve bir noktada bu PDF’ye çarpacağın ortaya çıktı . Hangi kesinlikle harika bir okuma, ancak okulda öğrendiğiniz tüm matematik şeylerini unutmuş olmanız durumunda (veya sadece bu matematiksel sembolleri sevmiyorsanız), bu oldukça işe yaramaz.
Şimdi ne var? Öyleyse git ve Google biraz daha oku (6 saat) ve sonunda konuyla ilgili harika bir makale buldun (güzel resimler dahil! ^ _ ^ "):
Http://www.planetclegg.com/projects/WarpingTextToSplines.html
Gerçek kodun yapılması
Eğer sadece PDF bulunuyor indirirken dayanamadı rağmen zaten uzun, çok uzun zaman önce senin matematik bilgisi kaybetmişler (ve atlamak için yönetilen büyük bir makale linki), şimdi düşünebilir: "Tanrı, bu alacak Yüzlerce satır kod ve CPU
Hayır, olmaz. Çünkü tüm programcıların yaptıklarını, matematik işlerine gelince yapıyoruz :
Basitçe hile yapıyoruz.
Yay uzunluğu parametresi, tembel yol
Kabul edelim, oyunumuzda sonsuz bir hassasiyete ihtiyacımız yok, değil mi? Öyleyse Nasa'da çalışıyorsanız ve insanlara Mars'ı göndermeyi planlamıyorsanız, 0.000001 pixelmükemmel bir çözüme ihtiyacınız olmayacak .
Öyleyse nasıl harita oluşturuyorsunuz Tüzerine t? Çok basit ve sadece 3 adımdan oluşuyor:
NEğri üzerindeki noktaları hesaplayın tve arc-length(yani eğrinin uzunluğu) dizisini o konumda saklayın
Eşleştirmek için Tüzerine tilk çarpma, Talmak için eğrinin toplam uzunluğu ile uve daha sonra daha küçük büyük değer endeksi için uzunlukları dizi aramau
Kesin bir vuruş yaptıysak, bu indeks içindeki dizi değerini ikiye Nböldük, bulduğumuz nokta ile bir sonraki arasında bir bit arasına sokmazsanız, bir kez daha bölüp Ngeri dönün.
Bu kadar! Şimdi tüm kodu inceleyelim:
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;
}
Bu yeni eğrimizi başlatır ve hesaplar, arg-lenghtsayrıca uzunlukların sonunu total lengtheğrinin sonu olarak kaydeder, burada this.lenbizim anahtar faktörümüzdür N. Haritalama ne kadar yüksekse, haritalama o kadar kesin olacaktır, çünkü yukarıdaki resimdeki boyutun bir eğrisi 100 pointsyeterli olacaktır, eğer sadece uzun bir tahminde bulunmanız gerekiyorsa, bizim gibi bir şey 25zaten sadece 1 piksel kapalı olacak gibi yapacaktır. örnek, ama sonra bir o kadar da dağıtım sonuçlanacak bir az kesin eşleme olacak Teşleştirilmiş zaman 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));
},
Gerçek haritalama kodu, önce binary searchdaha küçük olan en büyük uzunluğu bulmak için depolanan uzunluklarımız üzerinde basit bir işlem yaparız targetLength, sonra sadece enterpolasyon ve geri dönüş yaparız.
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;
}
};
Yine bu t, eğri üzerinde hesaplar .
Sonuçların zamanı

Şimdi kullanarak mxve eğri üzerinde myeşit bir şekilde dağılmış olsun T:)
Zor değil miydi? Bir kez daha, basit (mükemmel bir çözüm olmasa da) bir oyun için yeterli olacağı ortaya çıktı.
Kodun tamamını görmek istiyorsanız, mevcut bir Gist vardır:
https://gist.github.com/670236
Sonunda gemileri hızlandırmak
Şimdi geriye kalan tek şey, gemileri yolunda hızlandırmak, Tdaha sonra teğrimizi bulmak için kullandığımız pozisyonu haritalamak .
Öncelikle ihtiyacımız iki hareket denklemlerinin , yani ut + 1/2at²ve(v - u) / t
Bu gibi görünen gerçek kodda:
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;
Sonra bunu 0...1yaparak aşağı doğru ölçeklendiririz :
maxPosition = 0.5 * acceleration + startSpeed;
newT = 1 / maxPosition * position;
Ve işte gidiyorsunuz, gemiler şimdi yol boyunca sorunsuz hareket ediyor.
İşe yaramazsa ...
Bunu okurken, her şey yolunda ve zahmetli çalışıyor, ama başlangıçta ivme bölümüyle ilgili bazı problemler yaşadım, sorunu gamedev sohbet odasındaki birine açıklarken düşüncelerimdeki son hatayı buldum.
Asıl sorudaki resim hakkında henüz bir şey unutmadıysanız, sorada belirtmek isterim ki, o dereces hızdır , ancak gemiler yol boyunca pikseller halinde hareket ederler ve ben de bu gerçeği unuttum. Bu durumda yapmam gereken, yer değiştirmeyi derece cinsinden piksel cinsinden yer değiştirmeye dönüştürmekti, bunun oldukça kolay olduğu ortaya çıktı:
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);
};
Demek hepsi bu! Okuduğunuz için teşekkürler;)