Euklidean vektor di Flash
Indonesian (Bahasa Indonesia) translation by Kang Abbad (you can also view the original English article)
Dua kali sebulan, kita kembali beberapa pembaca kami posting favorit dari Activetuts + sejarah. Minggu ini tutorial retro-aktif, pertama kali diterbitkan pada bulan April, adalah panduan untuk vektor Euklidean: apa yang mereka adalah, mengapa Anda akan menggunakannya dan bagaimana untuk mengimplementasikannya di Flash dengan AS3.
Euclidean vectors adalah objek dalam geometri dengan sifat-sifat tertentu yang sangat berguna untuk mengembangkan permainan. Mereka dapat dilihat sebagai poin, tetapi mereka juga memiliki besarnya dan arah. Mereka digambarkan sebagai panah pergi dari titik awal ke titik akhir, dan itu adalah bagaimana kita akan menarik mereka dalam artikel ini.
Euklidean vektor yang umum digunakan dalam matematika dan fisika untuk banyak hal: mereka dapat mewakili kecepatan, percepatan dan kekuatan dalam fisika, atau membantu membuktikan banyak teorema penting dalam matematika. Dalam tutorial ini, Anda akan belajar tentang Euklidean vektor, dan membangun sebuah kelas yang dapat Anda gunakan dalam proyek Anda sendiri Flash.
Harap dicatat bahwa vektor Euklidean berbeda dari ActionScript's Vektor class, dan juga berbeda dari vector drawing.
Vektor dapat digunakan dalam lingkungan Flash untuk membantu Anda mencapai tugas-tugas kompleks yang kalau tidak akan membutuhkan banyak upaya jika dilakukan tanpa mereka. Dalam artikel ini Anda akan mempelajari bagaimana untuk menggunakannya dalam Flash, serta belajar banyak trik keren dengan vektor.
Langkah 1: Koordinat Cartesian dan koordinat Flash
Sebelum melompat ke vektor, mari kita memperkenalkan sistem koordinat Flash. Anda mungkin akrab dengan sistem koordinat Kartesius (bahkan jika Anda tidak tahu itu berdasarkan nama):

Sistem Flash sangat mirip. Satu-satunya perbedaan adalah bahwa sumbu y terbalik:

Ketika kita mulai bekerja dengan vektor di flash, kita perlu ingat bahwa. Namun, Kabar baik: sistem ini berbeda tidak membuat banyak perbedaan. Bekerja dengan vektor di dalamnya akan pada dasarnya seperti bekerja dengan vektor dalam sistem Cartesian.
Langkah 2: Menentukan vektor
Untuk tutorial ini, kita akan mendefinisikan dan bekerja dengan semua vektor awal poin sebagai titik pendaftaran tahap, sama seperti mereka yang umum digunakan dalam matematika. Vektor kemudian dapat didefinisikan seperti titik yang umum, tetapi akan memiliki sifat besarnya dan sudut. Lihatlah beberapa contoh vektor didefinisikan dalam tahap:



Seperti yang Anda lihat, vektor diwakili oleh Panah, dan vektor masing-masing memiliki panjang (atau magnitude) dan titik sepanjang sudut tertentu. Ekor setiap vektor adalah pada titik pendaftaran (0, 0)
.
Kita akan menciptakan kelas EuclideanVector sederhana untuk tutorial ini, menggunakan kelas titik terus vektor koordinat. Mari kita membuat kelas dasar vektor sekarang:
1 |
|
2 |
package
|
3 |
{
|
4 |
import flash.geom.Point; |
5 |
|
6 |
public class EuclideanVector |
7 |
{
|
8 |
public var position:Point; |
9 |
public var magnitude:Number; |
10 |
public var angle:Number; |
11 |
|
12 |
public function EuclideanVector(endPoint:Point) |
13 |
{
|
14 |
position = endPoint; |
15 |
}
|
16 |
}
|
17 |
}
|
Selama tutorial ini, kita akan berbicara tentang arti dan arah vektor. Perhatikan bahwa arah hanya menentukan garis yang "berisi" vektor. Pengertian adalah apa yang mendefinisikan yang cara vektor poin sepanjang garis ini.
Langkah 3: Kebalikan dari vektor
Dalam tutorial ini kita akan menggunakan ekspresi "kebalikan dari vektor". Kebalikan dari vektor adalah lain vektor dengan besarnya sama dan arah, tetapi sebaliknya rasa. Yang diterjemahkan menjadi vektor dengan sinyal berlawanan koordinat vektor yang pertama. Jadi vektor dengan akhir dari (x, y) akan memiliki vektor invers dengan akhir dari (-x, -y).

Mari kita menambahkan fungsi kelas EuclideanVector kami kembali invers vektor:
1 |
|
2 |
public function inverse():EuclideanVector |
3 |
{
|
4 |
return new EuclideanVector(new Point(-position.x, -position.y)); |
5 |
}
|
Langkah 4: Operasi dasar penambahan
Sekarang bahwa kita telah belajar bagaimana untuk menentukan vektor, mari kita mempelajari cara menambahkan dua vektor: ini yang sederhana seperti menambahkan koordinat mereka secara terpisah. Lihatlah gambar ini:



Jika Anda melihat dalam gambar, adalah hasil dari penambahan dua vektor vektor yang lain, dan Anda dapat melihat bahwa koordinat jumlah koordinat dua vektor lainnya. Dalam kode, yang akan terlihat seperti ini:
1 |
|
2 |
public function sum(otherVector:EuclideanVector):EuclideanVector |
3 |
{
|
4 |
position.x += otherVector.position.x; |
5 |
position.y += otherVector.position.y; |
6 |
|
7 |
return this; |
8 |
}
|
Jadi kita dapat mengatakan bahwa:
1 |
|
2 |
vecR == vec1.sum(vec2); |
Langkah 5: Operasi dasar pengurangan
Pengurangan bekerja hampir sama dengan penambahan, tapi sebaliknya kita akan menambahkan inverse dari kedua vektor vektor yang pertama.



Hal ini sudah diketahui cara untuk jumlah dua vektor, jadi di sini adalah kode untuk pengurangan:
1 |
|
2 |
public function subtract(otherVector:EuclideanVector):EuclideanVector |
3 |
{
|
4 |
position.x -= otherVector.position.x; |
5 |
position.y -= otherVector.position.y; |
6 |
|
7 |
return this; |
8 |
}
|
Kode ini sangat berguna untuk mendapatkan vektor yang terjadi dari titik vektor ke titik lain. Melihat kembali pada gambar dan Anda akan melihat hal ini benar. Ini akan digunakan banyak dalam contoh berikutnya.
Langkah 6: Operasi dasar perkalian dengan nomor
Perkalian antara vektor dan sejumlah (nomor biasa dikenal sebagai "skalar" dalam vektor matematika) hasil dalam suatu vektor yang telah memiliki magnitudo dikalikan dengan jumlah ini, tetapi masih menunjuk ke arah yang sama; "mengulurkan" jika skalar lebih besar dari 1, dan tergencet jika skalar antara 0 dan 1. Rasa vektor baru akan sama dengan vektor asli jika skalar positif, atau sebaliknya jika negatif. Pada dasarnya, ini nomor "skala" vektor. Lihatlah gambar:

Dalam kode, kita hanya kalikan vektor koordinat oleh nomor, yang kemudian akan skala vektor:
1 |
|
2 |
public function multiply(number:Number):EuclideanVector |
3 |
{
|
4 |
position.x *= number; |
5 |
position.y *= number; |
6 |
|
7 |
return this; |
8 |
}
|
Langkah 7: Semakin besarnya vektor
Untuk mendapatkan sebuah vektor besarnya, kami akan menggunakan teorema Pythagoras. Jika Anda lupa apa itu, di sini adalah penyegar cepat:

Kode ini sangat sederhana:
1 |
|
2 |
public function magnitude():Number |
3 |
{
|
4 |
return Math.sqrt((position.x * position.x) + (position.y * position.y)); |
5 |
}
|
Anda juga harus menghapus publik var magnitude:Number
, karena ini adalah apa yang akan kita gunakan sekarang.
Besarnya vektor akan selalu menjadi positif, karena itu adalah akar kuadrat dari jumlah dari dua bilangan positif.
Langkah 8: Mendapatkan sudut vektor
Sudut vektor adalah sudut antara sumbu x dan vektor arah baris. Sudut diukur pergi dari sumbu x dan berputar anti-searah jarum jam sampai arah baris dalam sistem cartesian:



Namun, dalam Flash koordinat sistem, karena sumbu y terbalik, sudut ini akan diukur berputar searah jarum jam:



Ini dapat dengan mudah dihitung menggunakan kode berikut. Sudut akan dikembalikan radian, dalam kisaran 0-2pi. Jika Anda tidak tahu apa radian atau bagaimana menggunakannya, tutorial ini oleh Michael James Williams akan membantu Anda banyak.
1 |
|
2 |
public function angle():Number |
3 |
{
|
4 |
var angle:Number = Math.atan2(position.y, position.x); |
5 |
|
6 |
if (angle < 0) |
7 |
{
|
8 |
angle += Math.PI * 2; |
9 |
}
|
10 |
|
11 |
return angle; |
12 |
}
|
Langkah 9: Dot produk
Produk dot antara dua vektor adalah nomor dengan Rupanya ada artinya, tetapi memiliki dua kegunaan yang berguna. Pertama mari kita lihat bagaimana produk dot dapat dihitung:



Tapi itu juga dapat diperoleh dengan setiap vektor Koordinat:



Produk dot dapat memberitahu kita banyak tentang sudut antara vektor: jika itu positif, kemudian sudut berkisar dari 0 sampai 90 derajat. Jika negatif, sudut berkisar dari 90 sampai 180 derajat. Jika itu adalah nol, sudut adalah 90 derajat. Itu terjadi karena dalam formula pertama hanya kosinus bertanggung jawab untuk memberikan produk dot "sinyal": besaran selalu positif. Tetapi kita tahu bahwa kosinus positif berarti bahwa sudut berkisar dari 0 sampai 90 derajat, dan seterusnya untuk cosinus negatif dan zero.
Produk dot dapat juga digunakan untuk mewakili panjang vektor arah vektor lainnya. Menganggapnya sebagai proyeksi. Ini terbukti sangat berguna dalam hal-hal seperti Pemisahan Axis Theorem (SAT) dan implementasinya di AS3 untuk deteksi tabrakan dan respons dalam permainan.
Berikut adalah kode praktis untuk mendapatkan produk dot antara dua vektor:
1 |
|
2 |
public function dot(otherVector:EuclideanVector):Number |
3 |
{
|
4 |
return (position.x * otherVector.position.x) + (position.y * otherVector.position.y); |
5 |
}
|
Langkah 10: Terkecil sudut antara vektor
Sudut antara vektor, seperti yang terlihat dalam langkah 9, dapat diberikan oleh produk dot. Berikut adalah bagaimana menghitung:
1 |
|
2 |
public function angleBetween(otherVector:EuclideanVector):Number |
3 |
{
|
4 |
return Math.acos(dot(otherVector) / (magnitude() * otherVector.magnitude())); |
5 |
}
|
Langkah 11: Berkisar sudut antara vektor
Ada juga cara lain untuk menghitung sudut, yang memberikan hasil antara - pi dan pi dan selalu menghitung sudut yang berlangsung dari vektor pertama untuk kedua vektor; Hal ini berguna bila Anda ingin dengan mudah mengintegrasikan dengan rotasi layar objek (yang berkisar dari-180 ke 180).
Metode bekerja dengan mendapatkan sudut untuk kedua vektor, kemudian mengurangi sudut dan bekerja pada hasil.



Kode:
1 |
|
2 |
public function rangedAngleBetween(otherVector:EuclideanVector):Number |
3 |
{
|
4 |
var firstAngle:Number; |
5 |
var secondAngle:Number; |
6 |
|
7 |
var angle:Number; |
8 |
|
9 |
firstAngle = Math.atan2(otherVector.position.y, otherVector.position.x); |
10 |
secondAngle = Math.atan2(position.y, position.x); |
11 |
|
12 |
angle = secondAngle - firstAngle; |
13 |
|
14 |
while (angle > Math.PI) |
15 |
angle -= Math.PI * 2; |
16 |
while (angle < -Math.PI) |
17 |
angle += Math.PI * 2; |
18 |
|
19 |
return angle; |
20 |
}
|
Perhatikan bahwa sudut ini kembali positif jika secondAngle lebih tinggi dari firstAngle, jadi urutan di mana Anda mendapatkan sudut berkisar akan mempengaruhi hasil!
Langkah 12: Normalisasi vektor
Normalisasi vektor berarti membuat besarnya sama dengan 1, sambil tetap menjaga arah dan rasa vektor. Untuk melakukan itu, kita mengalikan vektor dengan 1 /magnitude
. Dengan begitu, besarnya akan berkurang, atau meningkat, menjadi 1.
1 |
|
2 |
public function normalize():EuclideanVector |
3 |
{
|
4 |
var m:Number = magnitude(); |
5 |
position.x /= m; |
6 |
position.y /= m; |
7 |
|
8 |
return this; |
9 |
}
|
Langkah 13: Mendapatkan Normal vektor
Normal dari vektor adalah vektor lain yang membuat sudut 90 derajat ke yang pertama. Ini dapat dihitung dengan rumus berikut:

Rumus bergantung pada kenyataan bahwa, karena normal selalu tegak lurus vektor, kita hanya perlu mengubah urutan x dan y koordinat dan balikkan salah satu dari mereka untuk mendapatkan normal. Gambar berikut menunjukkan proses:

Dalam gambar, Vec adalah vektor asli, Vec2 adalah vektor dengan koordinat bertukar Vec, dan Vec3 adalah vektor dengan koordinat y negatif Vec2. Ang dan Ang2 bervariasi, tetapi sudut antara Vec dan Vec3 selalu 90 derajat.
Dan kode sederhana
1 |
|
2 |
public function normalRight():EuclideanVector |
3 |
{
|
4 |
return new EuclideanVector(new Point(-position.y, position.x)); |
5 |
}
|
6 |
|
7 |
public function normalLeft():EuclideanVector |
8 |
{
|
9 |
return new EuclideanVector(new Point(position.y, -position.x)); |
10 |
}
|
Langkah 14: Berputar vektor
Untuk memutar vektor, kami menganggap (0, 0) posisi (titik awal) akan menjadi pusat rotasi. Titik diputar diberikan oleh rumus:



Formula ini diperoleh dengan menerapkan matriks putaran yang vektor. Kita akan pergi di luar cakupan tutorial ini jika kita pergi ke dalam matriks dan cara kerjanya, sehingga saya akan meninggalkan rumus di sini.
Kode ini cukup banyak yang sama:
1 |
|
2 |
public function rotate(angleInRadians:Number):EuclideanVector |
3 |
{
|
4 |
var newPosX:Number = (position.x * Math.cos(angleInRadians)) - (position.y * Math.sin(angleInRadians)); |
5 |
var newPosY:Number = (position.x * Math.sin(angleInRadians)) + (position.y * Math.cos(angleInRadians)); |
6 |
|
7 |
position.x = newPosX; |
8 |
position.y = newPosY; |
9 |
|
10 |
return this; |
11 |
}
|
Ini adalah akhir operasi vektor dasar kami. Apa yang akan Anda lihat selanjutnya adalah cara untuk menggunakan kelas ini melakukan hal-hal menarik. Berikut adalah kelas kami sejauh ini:
1 |
|
2 |
package
|
3 |
{
|
4 |
import flash.geom.Point; |
5 |
|
6 |
public class EuclideanVector |
7 |
{
|
8 |
public var position:Point; |
9 |
public var angle:Number; |
10 |
|
11 |
public function EuclideanVector(endPoint:Point) |
12 |
{
|
13 |
position = endPoint; |
14 |
}
|
15 |
|
16 |
public function inverse():EuclideanVector |
17 |
{
|
18 |
return new EuclideanVector(new Point(-position.x, -position.y)); |
19 |
}
|
20 |
|
21 |
public function sum(otherVector:EuclideanVector):EuclideanVector |
22 |
{
|
23 |
position.x += otherVector.position.x; |
24 |
position.y += otherVector.position.y; |
25 |
|
26 |
return this; |
27 |
}
|
28 |
|
29 |
public function subtract(otherVector:EuclideanVector):EuclideanVector |
30 |
{
|
31 |
position.x -= otherVector.position.x; |
32 |
position.y -= otherVector.position.y; |
33 |
|
34 |
return this; |
35 |
}
|
36 |
|
37 |
public function multiply(number:Number):EuclideanVector |
38 |
{
|
39 |
position.x *= number; |
40 |
position.y *= number; |
41 |
|
42 |
return this; |
43 |
}
|
44 |
|
45 |
public function magnitude():Number |
46 |
{
|
47 |
return Math.sqrt((position.x * position.x) + (position.y * position.y)); |
48 |
}
|
49 |
|
50 |
public function angle():Number |
51 |
{
|
52 |
var angle:Number = Math.atan2(position.y, position.x); |
53 |
|
54 |
if (angle < 0) |
55 |
{
|
56 |
angle += Math.PI * 2; |
57 |
}
|
58 |
|
59 |
return angle; |
60 |
}
|
61 |
|
62 |
public function dot(otherVector:EuclideanVector):Number |
63 |
{
|
64 |
return (position.x * otherVector.position.x) + (position.y * otherVector.position.y); |
65 |
}
|
66 |
|
67 |
public function angleBetween(otherVector:EuclideanVector):Number |
68 |
{
|
69 |
return Math.acos(dot(otherVector) / (magnitude() * otherVector.magnitude())); |
70 |
}
|
71 |
|
72 |
public function rangedAngleBetween(otherVector:EuclideanVector):Number |
73 |
{
|
74 |
var firstAngle:Number; |
75 |
var secondAngle:Number; |
76 |
|
77 |
var angle:Number; |
78 |
|
79 |
firstAngle = Math.atan2(otherVector.position.y, otherVector.position.x); |
80 |
secondAngle = Math.atan2(position.y, position.x); |
81 |
|
82 |
angle = secondAngle - firstAngle; |
83 |
|
84 |
while (angle > Math.PI) |
85 |
angle -= Math.PI * 2; |
86 |
while (angle < -Math.PI) |
87 |
angle += Math.PI * 2; |
88 |
|
89 |
return angle; |
90 |
}
|
91 |
|
92 |
public function normalize():EuclideanVector |
93 |
{
|
94 |
position.x /= magnitude(); |
95 |
position.y /= magnitude(); |
96 |
|
97 |
return this; |
98 |
}
|
99 |
|
100 |
public function normalRight():EuclideanVector |
101 |
{
|
102 |
return new EuclideanVector(new Point(-position.y, position.x)); |
103 |
}
|
104 |
|
105 |
public function normalLeft():EuclideanVector |
106 |
{
|
107 |
return new EuclideanVector(new Point(position.y, -position.x)); |
108 |
}
|
109 |
|
110 |
public function rotate(angleInRadians:Number):EuclideanVector |
111 |
{
|
112 |
var newPosX:Number = (position.x * Math.cos(angleInRadians)) - (position.y * Math.sin(angleInRadians)); |
113 |
var newPosY:Number = (position.x * Math.sin(angleInRadians)) + (position.y * Math.cos(angleInRadians)); |
114 |
|
115 |
position.x = newPosX; |
116 |
position.y = newPosY; |
117 |
|
118 |
return this; |
119 |
}
|
120 |
}
|
121 |
}
|
OK, kita telah membahas bangunan kelas vektor, sekarang mari kita mengambil mengambil di memanfaatkan.
Langkah 15: Menentukan apakah titik adalah dalam poligon
Aksi dimulai di sini. Menentukan apakah suatu titik terletak di dalam sebuah poligon atau tidak adalah topik yang sangat menarik, dan ada banyak metode untuk mencapainya. Dalam artikel ini saya akan menyajikan tiga metode yang umumnya digunakan:
- crossing number atau even-odd rule algorithm, yang menentukan apakah suatu titik berada di dalam poligon dari sejumlah sisi yang dilambangkan oleh "sinar" dari titik hingga persilangan tak terbatas.
- winding number algorithm, yang memberikan jawaban berdasarkan jumlah dari semua sudut yang dibentuk antara berturut-turut simpul dari sebuah poligon dan titik untuk memeriksa.
- convex polygon algorithm, yang, seperti namanya mengatakan, hanya bekerja untuk poligon cembung dan didasarkan pada apakah atau tidak titik adalah pada "sisi tertentu" dari setiap tepi poligon.
Semua algoritma ini akan bergantung pada kenyataan bahwa Anda tahu koordinat dari simpul (sudut) yang mendefinisikan poligon.
Langkah 16: Persimpangan aturan nomor atau bahkan-aneh algoritma
Algoritma ini dapat digunakan untuk setiap bentuk. Ini adalah apa yang Anda baca: berbagai bentuk, memiliki lubang atau tidak, baik itu convex atau tidak. Itu adalah didasarkan pada kenyataan bahwa setiap ray dilemparkan dari titik Anda mau check out ke infinity akan menyeberangi sebuah nomor genap tepi jika titik berada di luar bentuk, atau ganjil tepi jika titik dalam bentuk. Hal ini dapat dibuktikan oleh Jordan curve theorem, yang menyiratkan bahwa Anda akan memiliki untuk menyeberangi perbatasan antara beberapa wilayah dan wilayah lainnya jika Anda ingin pindah dari satu ke yang lain. Dalam kasus kami, wilayah kami adalah "dalam bentuk" dan "luar bentuk".



Kode untuk algoritma ini adalah sebagai berikut:
1 |
|
2 |
public function isPointInsideShape1(point:EuclideanVector, shapeVertices:Vector.<EuclideanVector>):Boolean |
3 |
{
|
4 |
var numberOfSides:int = shapeVertices.length; |
5 |
|
6 |
var i:int = 0; |
7 |
var j:int = numberOfSides - 1; |
8 |
|
9 |
var oddNodes:Boolean = false; |
10 |
|
11 |
while (i < numberOfSides) |
12 |
{
|
13 |
if ((shapeVertices[i].position.y < point.position.y && shapeVertices[j].position.y >= point.position.y) || |
14 |
(shapeVertices[j].position.y < point.position.y && shapeVertices[i].position.y >= point.position.y)) |
15 |
{
|
16 |
if (shapeVertices[i].position.x + (((point.position.y - shapeVertices[i].position.y) / (shapeVertices[j].position.y - shapeVertices[i].position.y)) * |
17 |
(shapeVertices[j].position.x - shapeVertices[i].position.x)) < point.position.x) |
18 |
{
|
19 |
oddNodes = !oddNodes; |
20 |
}
|
21 |
}
|
22 |
|
23 |
j = i; |
24 |
|
25 |
i++; |
26 |
}
|
27 |
|
28 |
return oddNodes; |
29 |
}
|
Itu akan return false
jika titik tidak dalam bentuk, atau true
jika titik adalah dalam bentuk.
Langkah 17: Gulungan nomor algoritma
winding number algorithm menggunakan jumlah dari semua sudut yang dibuat antara titik untuk memeriksa dan masing-masing sepasang poin yang mendefinisikan poligon. Jika jumlah yang dekat dengan 2pi, kemudian titik sedang diperiksa adalah dalam vektor. Jika sudah mendekati 0 kemudian titik berada di luar.

1 |
|
2 |
public function isPointInsideShape2(point:EuclideanVector, shapeVertices:Vector.<EuclideanVector>):Boolean |
3 |
{
|
4 |
var numberOfSides:int = shapeVertices.length; |
5 |
|
6 |
var i:int = 0; |
7 |
var angle:Number = 0; |
8 |
|
9 |
var rawAngle:Number = 0; |
10 |
|
11 |
var firstVector:EuclideanVector; |
12 |
var secondVector:EuclideanVector; |
13 |
|
14 |
while(i < numberOfSides) |
15 |
{
|
16 |
firstVector = new EuclideanVector(new Point(shapeVertices[i].position.x - point.position.x, shapeVertices[i].position.y - point.position.y)); |
17 |
secondVector = new EuclideanVector(new Point(shapeVertices[(i + 1) % numberOfSides].position.x - point.position.x, shapeVertices[(i + 1) % numberOfSides].position.y - point.position.y)); |
18 |
|
19 |
angle += secondVector.rangedAngleBetween(firstVector); |
20 |
|
21 |
i++; |
22 |
}
|
23 |
|
24 |
if(Math.abs(angle) < Math.PI) |
25 |
return false; |
26 |
else
|
27 |
return true; |
28 |
}
|
Kode menggunakan sudut berkisar antara vektor dan memberi ruang untuk imprecisions: perhatikan bagaimana kami memeriksa hasil jumlah dari semua sudut. Kami tidak memeriksa apakah sudut persis nol atau 2pi. Sebaliknya, kami memeriksa apakah kurang dari pi dan lebih tinggi daripada pi, nilai rata-rata cukup.
Langkah 18: Algoritma cekung poligon
concave polygon algorithm bergantung pada kenyataan bahwa, untuk sebuah poligon cekung, titik di dalamnya adalah selalu di sebelah kiri tepi (jika kita perulangan melalui mereka dalam arti berlawanan arah jarum jam) atau di sebelah kanan tepi (jika kita perulangan melalui mereka dalam arti searah jarum jam) .

Bayangkan berdiri di kamar berbentuk seperti gambar di atas, dan berjalan di sekitar tepi itu dengan tangan kiri Anda mengikuti sepanjang dinding. Pada titik sepanjang dinding mana terdekat ke titik Anda tertarik, jika di sebelah kanan Anda maka itu harus di dalam ruang; Jika di sebelah kiri Anda maka itu harus di luar.
Masalahnya terletak dalam menentukan apakah suatu titik ke kiri atau kanan tepi (yang pada dasarnya vektor). Hal ini dilakukan melalui rumus berikut:



Bahwa formula kembali kurang nomor dari 0 untuk menunjuk ke kanan tepi, dan lebih besar dari 0 untuk poin ke kiri itu. Jika nomornya sama dengan 0, titik terletak di tepi, dan dianggap dalam bentuk. Kode adalah sebagai berikut:
1 |
|
2 |
public function isPointInsideShape3(point:EuclideanVector, shapeVertices:Vector.<EuclideanVector>):Boolean |
3 |
{
|
4 |
var numberOfSides:int = shapeVertices.length; |
5 |
|
6 |
var i:int = 0; |
7 |
|
8 |
var firstEdgePoint:EuclideanVector; |
9 |
var secondEdgePoint:EuclideanVector; |
10 |
|
11 |
var leftOrRightSide:Boolean; |
12 |
|
13 |
while(i < numberOfSides) |
14 |
{
|
15 |
firstEdgePoint = shapeVertices[i]; |
16 |
secondEdgePoint = shapeVertices[(i + 1) % numberOfSides]; |
17 |
|
18 |
if(i == 0) |
19 |
{
|
20 |
// Determining if the point is to the left or to the right of first edge
|
21 |
// true for left, false for right
|
22 |
|
23 |
leftOrRightSide = ((point.position.y - firstEdgePoint.position.y) * (secondEdgePoint.position.x - firstEdgePoint.position.x)) - ((point.position.x - firstEdgePoint.position.x) * (secondEdgePoint.position.y - firstEdgePoint.position.y)) > 0; |
24 |
}
|
25 |
else
|
26 |
{
|
27 |
// Now all edges must be on the same side
|
28 |
|
29 |
if(leftOrRightSide && ((point.position.y - firstEdgePoint.position.y) * (secondEdgePoint.position.x - firstEdgePoint.position.x)) - ((point.position.x - firstEdgePoint.position.x) * (secondEdgePoint.position.y - firstEdgePoint.position.y)) < 0) |
30 |
{
|
31 |
// Not all edges are on the same side!
|
32 |
|
33 |
return false; |
34 |
}
|
35 |
else if(!leftOrRightSide && ((point.position.y - firstEdgePoint.position.y) * (secondEdgePoint.position.x - firstEdgePoint.position.x)) - ((point.position.x - firstEdgePoint.position.x) * (secondEdgePoint.position.y - firstEdgePoint.position.y)) > 0) |
36 |
{
|
37 |
// Not all edges are on the same side!
|
38 |
|
39 |
return false; |
40 |
}
|
41 |
}
|
42 |
|
43 |
i++; |
44 |
}
|
45 |
|
46 |
// We looped through all vertices and didn't detect different sides
|
47 |
|
48 |
return true; |
49 |
}
|
Kode ini bekerja terlepas dari Apakah Anda memiliki bentuk yang simpul didefinisikan searah jarum jam atau berlawanan arah jarum jam.
Langkah 19: Ray Casting
Ray pengecoran adalah teknik yang sering digunakan untuk deteksi tabrakan dan rendering. Terdiri dari sinar yang dilemparkan dari satu tempat ke yang lain (atau keluar tanpa batas). Ray ini terbuat dari poin atau vektor, dan umumnya berhenti ketika hits objek atau tepi layar. Sama dengan algoritma titik dalam bentuk, ada banyak cara untuk pemain sinar, dan kita akan melihat dua dari mereka dalam posting ini:
- Bresenham baris algoritma, yang merupakan cara yang sangat cepat untuk menentukan tutup poin yang akan memberikan perkiraan garis antara mereka.
- Metode DDA (Digital diferensial Analyzer), yang juga digunakan untuk membuat garis.
Dalam dua langkah kita akan melihat ke kedua metode. Setelah itu, kita akan melihat bagaimana membuat ray kami berhenti ketika hits objek. Hal ini sangat berguna ketika Anda perlu untuk mendeteksi tabrakan terhadap benda bergerak cepat.
Langkah 20: Bresenham Line algoritma
Algoritma ini sangat sering digunakan dalam komputer grafis, dan tergantung pada Konvensi bahwa garis akan selalu dibuat menunjuk ke kanan dan ke bawah. (Jika garis telah dibuat ke arah atas dan kiri, semuanya terbalik kemudian.) Mari kita pergi ke dalam kode:
1 |
|
2 |
public function createLineBresenham(startVector:EuclideanVector, endVector:EuclideanVector):Vector.<EuclideanVector> |
3 |
{
|
4 |
var points:Vector.<EuclideanVector> = new Vector.<EuclideanVector>(); |
5 |
|
6 |
var steep:Boolean = Math.abs(endVector.position.y - startVector.position.y) > Math.abs(endVector.position.x - startVector.position.x); |
7 |
|
8 |
var swapped:Boolean = false; |
9 |
|
10 |
if (steep) |
11 |
{
|
12 |
startVector = new EuclideanVector(new Point(startVector.position.y, startVector.position.x)); |
13 |
endVector = new EuclideanVector(new Point(endVector.position.y, endVector.position.x)); |
14 |
}
|
15 |
|
16 |
// Making the line go downward
|
17 |
if (startVector.position.x > endVector.position.x) |
18 |
{
|
19 |
var temporary:Number = startVector.position.x; |
20 |
|
21 |
startVector.position.x = endVector.position.x; |
22 |
|
23 |
endVector.position.x = temporary; |
24 |
|
25 |
temporary = startVector.position.y; |
26 |
|
27 |
startVector.position.y = endVector.position.y |
28 |
|
29 |
endVector.position.y = temporary; |
30 |
|
31 |
swapped = true; |
32 |
}
|
33 |
|
34 |
var deltaX:Number = endVector.position.x - startVector.position.x; |
35 |
var deltaY:Number = Math.abs(endVector.position.y - startVector.position.y); |
36 |
|
37 |
var error:Number = deltaX / 2; |
38 |
|
39 |
var currentY:Number = startVector.position.y; |
40 |
|
41 |
var step:int; |
42 |
|
43 |
if (startVector.position.y < endVector.position.y) |
44 |
{
|
45 |
step = 1; |
46 |
}
|
47 |
else
|
48 |
{
|
49 |
step = -1; |
50 |
}
|
51 |
|
52 |
var iterator:int = startVector.position.x; |
53 |
|
54 |
while (iterator < endVector.position.x) |
55 |
{
|
56 |
if (steep) |
57 |
{
|
58 |
points.push(new EuclideanVector(new Point(currentY, iterator))); |
59 |
}
|
60 |
else
|
61 |
{
|
62 |
points.push(new EuclideanVector(new Point(iterator, currentY))); |
63 |
}
|
64 |
|
65 |
error -= deltaY; |
66 |
|
67 |
if (error < 0) |
68 |
{
|
69 |
currentY += step; |
70 |
error += deltaX; |
71 |
}
|
72 |
|
73 |
iterator++; |
74 |
}
|
75 |
|
76 |
if (swapped) |
77 |
{
|
78 |
points.reverse(); |
79 |
}
|
80 |
|
81 |
return points; |
82 |
}
|
Kode tersebut akan menghasilkan AS3 Vektor atau Euclidean vecktor yang akan membuat garis. Dengan Vector ini, kita dapat memeriksa tabrakan nantinya.
Langkah 21: Metode DDA
Sebuah implementasi dari Analyzer diferensial Digital digunakan untuk melakukan interpolasi variabel antara dua titik. Tidak seperti Bresenham garis algoritma, metode ini hanya akan menciptakan vektor bilangan bulat posisi untuk kesederhanaan. Berikut adalah kode:
1 |
|
2 |
public function createLineDDA(startVector:EuclideanVector, endVector:EuclideanVector):Vector.<EuclideanVector> |
3 |
{
|
4 |
var points:Vector.<EuclideanVector> = new Vector.<EuclideanVector>(); |
5 |
|
6 |
var dx:Number; |
7 |
var dy:Number; |
8 |
|
9 |
var _x:Number = startPoint.position.x; |
10 |
var _y:Number = startPoint.position.y; |
11 |
|
12 |
var m:Number; |
13 |
|
14 |
var i:int; |
15 |
|
16 |
dx = endPoint.position.x - startPoint.position.x; |
17 |
dy = endPoint.position.y - startPoint.position.y; |
18 |
|
19 |
if (Math.abs(dx) >= Math.abs(dy)) |
20 |
m = Math.abs(dx); |
21 |
else
|
22 |
m = Math.abs(dy); |
23 |
|
24 |
points.push(new EuclideanVector(new Point(int(_x), int(_y)))); |
25 |
|
26 |
i = 1; |
27 |
|
28 |
while (i <= m) |
29 |
{
|
30 |
_x += dx / m; |
31 |
_y += dy / m; |
32 |
|
33 |
points.push(new EuclideanVector(new Point(int(_x), int(_y)))); |
34 |
|
35 |
i++; |
36 |
}
|
37 |
|
38 |
return points; |
39 |
}
|
Kode ini juga akan kembali AS3 Vektor vektor Euklidean.
Langkah 22: Memeriksa tabrakan menggunakan sinar
Memeriksa tabrakan melalui sinar ini sangat sederhana. Karena sinar terdiri dari banyak vektor, kita akan memeriksa tabrakan antara setiap vektor dan bentuk yang, sampai satu terdeteksi atau mencapai bagian akhir sinar. Dalam kode berikut, shapeToCheck
akan menjadi bentuk yang sama seperti yang kita telah menggunakan langkah 13-16. Berikut adalah kode:
1 |
|
2 |
public function checkRayCollision(ray:Vector.<EuclideanVector>, shape:Vector.<EuclideanVector>):Boolean |
3 |
{
|
4 |
var rayLength:int = ray.length; |
5 |
|
6 |
var i:int = 0; |
7 |
|
8 |
while(i < rayLength) |
9 |
{
|
10 |
if(isPointInsideShape1(ray[i], shape)) |
11 |
{
|
12 |
return true; |
13 |
}
|
14 |
|
15 |
i++; |
16 |
}
|
17 |
|
18 |
return false; |
19 |
}
|
Anda dapat menggunakan fungsi titik berbentuk dalam apapun yang Anda merasa nyaman dengan, tetapi membayar perhatian keterbatasan terakhir!
Kesimpulan
Anda siap untuk mulai menggunakan pengetahuan ini di mana-mana sekarang! Ini akan berguna berkali-kali, dan akan menghemat banyak perhitungan tambahan ketika mencoba untuk melakukan hal-hal yang lebih kompleks di Flash.