ঠিক আছে, আমি সবকিছু কাজ করে ফেলেছি, এটি চিরকাল নিয়ে গেছে, তাই আমি এখানে আমার বিস্তারিত সমাধান পোস্ট করব।
দ্রষ্টব্য: সমস্ত কোডের নমুনা জাভাস্ক্রিপ্টে রয়েছে।
সুতরাং আসুন সমস্যাটিকে মূল অংশগুলিতে ভাঙি:
আপনাকে 0..1
বেজিয়ার বক্ররেখার দৈর্ঘ্যের পাশাপাশি পয়েন্টগুলিও গণনা করতে হবে
T
জাহাজটিকে এক গতি থেকে অন্য গতিতে গতি বাড়ানোর জন্য আপনার এখন স্কেলিং সামঞ্জস্য করতে হবে
সঠিকভাবে বেজিয়ার পাচ্ছেন
বেজিয়ার কার্ভ আঁকার জন্য কিছু কোড সন্ধান করা সহজ, এখানে বিভিন্ন ধরণের পন্থা রয়েছে যদিও এর মধ্যে একটি হ'ল ডেস্কটেলজৌ অ্যালগোরিদম , তবে আপনি কেবল ঘনক বেজিয়ার বক্ররেখার জন্য সমীকরণটিও ব্যবহার করতে পারেন :
// 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;
}
এটির সাহায্যে এখন কেউ কল করে বেজিয়র বক্ররেখা আঁকতে পারে x
এবং এর মধ্য y
দিয়ে t
কীভাবে আসে 0 to 1
তা একবার দেখে নেওয়া যাক:
আহ ... এটি সত্যিই পয়েন্টগুলির এমনকি বিতরণ নয়, তাই না?
বাজিয়ার বক্রের প্রকৃতির কারণে, বিন্দুগুলি 0...1
আলাদা থাকে arc lenghts
, সুতরাং শুরু এবং শেষের কাছাকাছি বিভাগগুলি বক্রাকার মধ্যবর্তী কাছাকাছি অবস্থিত দীর্ঘগুলির চেয়ে দীর্ঘ হয়।
বক্ররেখার একে একে দৈর্ঘ্যের পরামিতিগুলিতে সমানভাবে ম্যাপিং টি
তো এখন কি করা? ভাল সরল কথায়, আমাদের বক্ররেখার T
উপর আমাদের মানচিত্র তৈরি করার জন্য একটি ফাংশন প্রয়োজন t
, যাতে আমাদের T 0.25
ফলাফলটি বক্রের দৈর্ঘ্যের t
স্থানে থাকে 25%
।
আমরা যে কিভাবে করব? ওয়েল, আমরা Google ... কিন্তু এটা দেখা যাচ্ছে যে শব্দটি না যে googleable , এবং কিছু সময়ে আপনি এই আঘাত করব পিডিএফ । কোনটি নিশ্চিতভাবে পঠনযোগ্য, তবে আপনি স্কুলে ফিরে পড়া সমস্ত গণিতের জিনিসগুলি ইতিমধ্যে ভুলে গেছেন (বা আপনি কেবল সেই গাণিতিক প্রতীক পছন্দ করেন না) এটি বেশ অকেজো।
এখন কি? ভাল যান এবং গুগল আরও কিছু পড়ুন (পড়ুন: 6 ঘন্টা), এবং আপনি অবশেষে এই বিষয়ের উপর একটি দুর্দান্ত নিবন্ধটি পেয়েছেন (সুন্দর ছবি সহ! ^ _ ^ "):
Http://www.planetclegg.com/projects/WarpingTextToSplines.html
আসল কোড করছে
আপনি যদি এই পিডিএফটি ডাউনলোড করতে কেবলমাত্র প্রতিরোধ করতে না পারেন যদিও আপনি ইতিমধ্যে আপনার গাণিতিক জ্ঞানটি দীর্ঘ, দীর্ঘ, অনেক আগে হারিয়ে ফেলেছিলেন (এবং আপনি দুর্দান্ত নিবন্ধের লিঙ্কটি এড়িয়ে যেতে সক্ষম হয়েছেন ), আপনি এখন ভাবতে পারেন: "Godশ্বর, এটি গ্রহণ করবে কয়েকশো লাইন কোড এবং টন সিপিইউ "
না এটা হবে না. কারণ আমরা যখন সমস্ত প্রোগ্রামাররা করি তা করি, যখন গণিতের জিনিস আসে:
আমরা কেবল প্রতারণা করি।
আর্ক-দৈর্ঘ্যের প্যারামিটারাইজেশন, অলস উপায়
আসুন এটির মুখোমুখি হোন, আমাদের গেমটিতে আমাদের অন্তহীন নির্ভুলতার প্রয়োজন নেই, তাই না? সুতরাং আপনি যদি নাসায় কাজ না করে এবং মানুষকে মঙ্গল গ্রহে প্রেরণের পরিকল্পনা না করেন তবে আপনার কোনও 0.000001 pixel
সঠিক সমাধানের প্রয়োজন হবে না ।
সুতরাং আমরা কিভাবে মানচিত্র না T
সম্মুখের t
? এটি সহজ এবং কেবল 3 টি পদক্ষেপ নিয়ে গঠিত:
N
বক্ররেখার পয়েন্টগুলি গণনা করুন t
এবং arc-length
সেই অবস্থানটিতে অ্যারেতে (বক্ররের দৈর্ঘ্য) ব্যবহার করুন
মানচিত্রে T
সম্মুখের t
, প্রথম সংখ্যাবৃদ্ধি T
বক্ররেখা মোট দৈর্ঘ্য দ্বারা পেতে u
এবং তারপর বৃহত্তম মান চেয়ে ছোট যে এর সূচির জন্য লেন্থ অ্যারে অনুসন্ধানu
আমাদের যদি সঠিক আঘাত লেগে থাকে তবে সেই সূচকটিতে অ্যারের মানটি ভাগ করে N
ফিরে আসুন, যদি আমরা যে পয়েন্টটি পেয়েছি এবং পরেরটির মধ্যে কিছুটা বিভক্ত না করে আবার জিনিসটি আবার ভাগ করে ফিরুন N
।
এখানেই শেষ! সুতরাং এখন সম্পূর্ণ কোডটি একবার দেখুন:
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;
}
এটি আমাদের নতুন বক্ররেখা সূচনা করে এবং গণনা করে arg-lenghts
, এটি দৈর্ঘ্যের শেষটি total length
বক্ররেখার হিসাবে সংরক্ষণ করে , এখানে মূল ফ্যাক্টরটি this.len
আমাদের N
। উপরের ছবিটির আকারের একটি বক্ররেখার জন্য যত বেশি উচ্চতর, তত বেশি যথাযথ হবে 100 points
, আপনার যদি কেবল একটি ভাল দৈর্ঘ্যের প্রাক্কলনের প্রয়োজন 25
হয় তবে আমাদের মতো 1 পিক্সেল বন্ধ থাকার মতো কিছু ইতিমধ্যে কাজটি করবে our উদাহরণস্বরূপ, তবে তারপরে আপনার কাছে একটি সুনির্দিষ্ট ম্যাপিং থাকবে যার ফলস্বরূপ ম্যাপিংয়ের সময় এতটা T
বিতরণও হবে না 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));
},
আসল ম্যাপিং কোড, প্রথমে আমরা binary search
আমাদের সঞ্চিত দৈর্ঘ্যের উপর সেক্ষেত্রে সবচেয়ে ছোট দৈর্ঘ্যের চেয়ে ছোট একটি সন্ধান targetLength
করি, তারপরে আমরা কেবল ফিরে আসি বা ঘূর্ণনটি ঘটিয়ে ফিরে যাই return
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;
}
};
আবার এই t
বক্ররেখা গণনা ।
ফলাফলের জন্য সময়
এখনই ব্যবহার করে mx
এবং my
আপনি T
বক্ররেখায় সমানভাবে বিতরণ করবেন :)
এত শক্ত ছিল না, তাই না? আবার, দেখা যাচ্ছে যে একটি সাধারণ (যদিও নিখুঁত সমাধান নয়) একটি গেমের জন্য যথেষ্ট।
আপনি যদি সম্পূর্ণ কোডটি দেখতে চান তবে একটি গিস্ট পাওয়া যায়:
https://gist.github.com/670236
অবশেষে, জাহাজগুলিকে ত্বরান্বিত করছে
সুতরাং এখন যা যা রয়েছে তা হ'ল জাহাজগুলিকে তাদের পথ ধরে ত্বরান্বিত করা, অবস্থানটি ম্যাপিংয়ের T
পরে আমরা t
আমাদের বক্ররেখার সন্ধান করতে ব্যবহার করি ।
প্রথমে আমাদের দুটি গতির সমীকরণ প্রয়োজন , যথা ut + 1/2at²
এবং এবং(v - u) / t
প্রকৃত কোডে এটির মতো দেখতে:
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;
তারপরে আমরা তা করে স্কেল করব 0...1
:
maxPosition = 0.5 * acceleration + startSpeed;
newT = 1 / maxPosition * position;
এবং সেখানে আপনি যান, জাহাজগুলি এখন পথ ধরে সুচারুভাবে এগিয়ে চলছে।
যদি এটি কাজ না করে ...
আপনি যখন এটি পড়ছেন, সবকিছু ঠিকঠাক এবং ছদ্মবেশী কাজ করে তবে গেমদেব চ্যাটরুমের কাউকে সমস্যাটি ব্যাখ্যা করার সময় আমি আমার চিন্তায় চূড়ান্ত ত্রুটিটি পেয়েছি accele
যদি আপনি ইতিমধ্যে মূল প্রশ্নের চিত্রটি সম্পর্কে ভুলে যান না, তবে আমি s
সেখানে উল্লেখ করেছি , s
এটি ডিগ্রিগুলির গতিতে পরিণত হয় , তবে জাহাজগুলি পিক্সেলের পথ ধরে এগিয়ে যায় এবং আমি সেই সত্যটি ভুলে গিয়েছিলাম। সুতরাং এই ক্ষেত্রে আমার যা করার দরকার ছিল তা হ'ল ডিগ্রিতে স্থানচ্যুতিটিকে পিক্সেলের একটি বাস্তুচ্যুতে রূপান্তরিত করা, দেখা যাচ্ছে এটি বরং সহজ:
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);
};
তো আর এটাই! পড়ার জন্য ধন্যবাদ ;)