Advertisement
  1. Code
  2. ActionScript

Matematika dan ActionScript kurva: gradien dan orang normal

Scroll to top
Read Time: 12 min

() translation by (you can also view the original English article)

Kami telah menangani menggambar kurva, dan menemukan akar kuadrat dan kubik, serta aplikasi berguna untuk menggunakan akar kuadrat dalam permainan. Sekarang, seperti yang dijanjikan, kita akan melihat aplikasi untuk menemukan akar kubik, serta gradien kurva dan orang normal, seperti membuat benda-benda yang memantul dari permukaan melengkung. Ayo!


Contoh

Mari kita melihat satu penggunaan praktis matematika ini:

Dalam demo ini, "kapal" memantul dari tepi SWF dan kurva. Titik kuning mewakili titik terdekat ke kapal yang terletak pada kurva. Anda dapat menyesuaikan bentuk kurva dengan menyeret titik merah, dan menyesuaikan gerakan kapal menggunakan tombol panah.


Langkah 1: Jarak terpendek untuk kurva

Mari kita mempertimbangkan skenario di mana titik berada dekat kurva kuadrat. Bagaimana Anda menghitung jarak terpendek antara titik dan kurva?

point to quadratic distance

Yah, mari kita mulai dengan teorema Pythagoras's.

\[
Let\ the\ point\ be\ (x_p, \ y_p) \\
and\ call\ the\ closest\ point\ on\ the\ curve\ (x_c, \ y_c) \\
Kemudian: \\
z ^ 2 = x ^ 2 + y ^ 2\\
z ^ 2 = (x_c-x_p) ^ 2 + (y_c-y_p) ^ 2\\
Given\ y_c = ax_c ^ 2 + bx_c + c, \\
z ^ 2 = (x_c-x_p) ^ 2 + [(ax_c ^ 2 + bx_c + c)-y_p] ^ 2
\]

Anda dapat melihat bahwa kita telah menggantikan \(y_c\) dengan Persamaan kuadrat. Sekilas, kita dapat melihat kekuasaan tertinggi adalah 4. Dengan demikian, kami memiliki persamaan quartic. Semua yang perlu kita lakukan adalah untuk menemukan titik minimal dalam persamaan ini memberi kita jarak terpendek dari titik untuk kurva kuadrat.

Tapi sebelum itu, kita harus memahami gradien pada kurva...


Langkah 2: Gradient kurva

Sebelum kita melihat masalah meminimalkan persamaan quartic, mari kita coba untuk mengerti gradien kurva. Garis lurus memiliki hanya satu gradien. Tetapi kurva kuadrat gradien tergantung pada titik mana pada kurva kita merujuk. Periksa Flash presentasi di bawah ini:

Seret titik-titik merah sekitar untuk mengubah kurva kuadrat. Anda juga dapat bermain dengan slider's pegangan untuk mengubah posisi titik biru sepanjang x. Sebagai titik biru perubahan, sehingga akan gradien ditarik.


Langkah 3: Gradient melalui kalkulus

Ini adalah di mana kalkulus akan datang berguna. Anda mungkin menebak bahwa membedakan Persamaan kuadrat akan memberikan Anda gradien kurva.

\[
f (x) = ax ^ 2 + bx + c\\
\frac{DF(x)} {dx} = 2ax + b
\]

Jadi \(\frac{df(x)}{dx}\) adalah gradien kurva kuadrat, dan itu tergantung pada koordinat \(x\). Yah, hal baik yang kita punya sebuah metode untuk menangani hal ini: diff1(x:Number) akan kembali nilai setelah diferensiasi tunggal.

Menggambar gradien, kita akan membutuhkan sebuah persamaan untuk mewakili baris, \(y=mx+c\). Koordinat titik biru \ ((x_p, y_p) \) akan diganti ke \(x\) dan \(y\), dan gradien baris ditemukan melalui diferensiasi akan pergi ke \(m\). Dengan demikian sumbu y garis, \(c\) dapat dihitung melalui beberapa pekerjaan aljabar.

Memeriksa AS3:

1
2
var x:Number = s.value
3
var y:Number = quadratic_equation.fx_of(s.value)
4
point.x = x;
5
point.y = y;
6
7
/**

8
 * y = mx + c;

9
 * c = y - mx;  <== use this to find c

10
 */
11
var m:Number = quadratic_equation.diff1(x);
12
var c:Number =  y - m * x;
13
14
graphics.clear();
15
graphics.lineStyle(1, 0xff0000);
16
graphics.moveTo(0, c);
17
graphics.lineTo(stage.stageWidth, m * stage.stageWidth + c);

Langkah 4: koordinat sistem

Selalu diingat dari sumbu-y terbalik Flash mengkoordinasikan ruang seperti yang ditunjukkan pada gambar di bawah ini. Pada pandangan pertama, diagram di kanan mungkin tampak seperti gradien negatif - tapi karena sumbu-y terbalik, adalah benar-benar gradien yang positif.

Positive gradient.

Sama berlaku untuk titik minimum seperti yang ditunjukkan di bawah ini. Karena sumbu-y terbalik, minimal titik dalam koordinat Kartesius ruang (di (0,0)) sepertinya maksimum di Flash mengkoordinasikan ruang. Tapi oleh merujuk ke lokasi yang asal di Flash mengkoordinasikan ruang relatif terhadap kurva kuadrat, ini adalah benar-benar titik minimal.

Positive gradient.Positive gradient.Positive gradient.

Langkah 5: Laju perubahan untuk gradien

Sekarang mari kita katakan saya tertarik untuk mencari titik terendah pada kurva - bagaimana harus saya lakukan? Lihat gambar di bawah ini (kedua tokoh berada di ruang koordinat yang sama).

Positive gradient.Positive gradient.Positive gradient.

Untuk mendapatkan titik minimum, kita hanya akan menyamakan \(\frac{df(x)} {dx} = 0\), karena menurut definisi kami sedang mencari titik di mana gradien nol. Tapi seperti yang ditunjukkan di atas, ternyata bahwa titik maksimum pada kurva juga memenuhi kondisi ini. Jadi bagaimana kita membedakan antara dua kasus ini?

Mari kita coba diferensiasi dari tingkat kedua. Ini akan memberi kita laju perubahan gradiasi.

\[
\frac{DF(x)} {dx} = 2ax + b\\
\frac{DF^2(x)} {dx ^ 2} = 2a
\]

Saya akan menjelaskan dengan mengacu pada gambar di bawah ini (diambil di ruang koordinat Kartesius). Kita dapat melihat bahwa, ketika kita kenaikan sepanjang sumbu x, gradien perubahan dari negatif ke positif. Jadi laju perubahan harus nilai positif.

Kita juga dapat melihat bahwa ketika \(\frac{df^2(x)}{dx^2}\) positif, ada titik minimum pada kurva. Sebaliknya jika nilai negatif, titik maksimum hadir.

Rate of change in gradient.Rate of change in gradient.Rate of change in gradient.

Langkah 6: kembali ke masalah

Sekarang kami siap untuk memecahkan masalah yang disajikan dalam langkah 1. Mengingat persamaan quartic (di mana tingkat tertinggi adalah 4) kami tiba di:

\[
z ^ 2 = (x_c-x_p) ^ 2 + [(ax_c ^ 2 + bx_c + c)-y_p] ^ 2
\]

quartic curvequartic curvequartic curve

Persamaan quartic sama, diplot

Ingat, kami tertarik untuk menemukan titik yang minimum pada kurva ini, karena titik yang sesuai pada kurva kuadrat asli akan menjadi titik yang di jarak minimum dari titik merah.

point to quadratic distance

Jadi, mari kita membedakan fungsi quartic untuk mendapatkan ke gradien kurva ini, dan kemudian menyamakan gradien fungsi ini quartic ke nol. Anda akan melihat bahwa gradien adalah benar-benar fungsi kubik. Saya akan sebut pembaca tertarik Wolfram di Halaman; untuk tutorial ini, saya hanya akan memetik hasil kerja aljabar mereka:

\[
\frac{d(z^2)} {dx} =
2(x_c-x_p) + 2 (ax_c ^ 2 + bx_c + c - y_p)(2ax_c+b) \\
\frac{d(z^2)} {dx} = 2a^2(x_c)^3+3ab(x_c)^2+(b^2+2ac-2ay_p+1) (x_c) + (SM-by_p-x_p) \\
Equate\ gradient\ to\ 0\\
\frac{d(z^2)} {dx} = 0\\
2A^2(x_c)^3+3ab(x_c)^2+(b^2+2ac-2ay_p+1) (x_c) + (SM-by_p-x_p) = 0\\
Compare\ with\ cubic\ equation\\
Ax ^ 3 + Bx ^ 2 + Cx + D = 0\\
A = 2a ^ 2\\
B = 3ab\\
C = b ^ 2 + 2ac-2ay_p + 1\\
D = SM-by_p-x_p
\]

Memecahkan untuk akar fungsi kubik (agak berantakan) ini dan kita akan tiba di koordinat titik biru tiga sebagaimana ditunjukkan di atas.

Selanjutnya, bagaimana kita menyaring hasil kami untuk titik minimum? Ingat dari langkah sebelumnya bahwa titik minimal memiliki tingkat perubahan yang positif. Untuk mendapatkan ini tingkat perubahan, membedakan fungsi kubik yang mewakili gradien. Jika laju perubahan untuk titik biru yang diberikan positif, itu adalah salah satu poin yang minimal. Untuk mendapatkan titik minimum, salah satu yang kami tertarik, memilih titik dengan tingkat tertinggi dari perubahan.


Langkah 7: Contoh output

Jadi di sini adalah sampel pelaksanaan ide yang dijelaskan di atas. Anda dapat menyeret titik-titik merah di sekitar untuk menyesuaikan kurva Anda kuadrat. Titik biru juga dapat diseret. Ketika Anda bergerak titik biru, kuning satu akan reposisi sehingga jarak antara titik biru dan kuning akan minimal antara semua poin pada kurva.

Seperti yang Anda berinteraksi dengan Flash presentasi, mungkin ada saat dimana tiga titik-titik kuning muncul sekaligus. Dua ini, memudar, mengacu kepada akar Diperoleh dari perhitungan tetapi ditolak karena mereka tidak titik terdekat di curve dot biru.


Langkah 8: ActionScript implementasi

Jadi di sini adalah penerapan ActionScript di atas. Anda dapat menemukan script lengkap di Demo2.as.

Pertama-tama kita harus menggambar kurva kuadrat. Perhatikan bahwa m2 matriks akan disebut untuk perhitungan lebih lanjut.

1
2
private function redraw_quadratic_curve():void 
3
{
4
    var cmd:Vector.<int> = new Vector.<int>;
5
    var coord:Vector.<Number> = new Vector.<Number>;
6
    
7
    //redraw curve;

8
    m1 = new Matrix3d(
9
        curve_points[0].x * curve_points[0].x, curve_points[0].x, 1, 0,
10
        curve_points[1].x * curve_points[1].x, curve_points[1].x, 1, 0,
11
        curve_points[2].x * curve_points[2].x, curve_points[2].x, 1, 0,
12
        0,0,0,1
13
    );
14
    
15
    m2 = new Matrix3d(
16
        curve_points[0].y, 0, 0, 0,
17
        curve_points[1].y, 0, 0, 0,
18
        curve_points[2].y, 0, 0, 0,
19
        0,0,0,1
20
    )
21
    
22
    m1.invert();
23
    m2.append(m1);
24
    quadratic_equation.define(m2.n11, m2.n21, m2.n31);
25
    
26
    for (var i:int = 0; i < stage.stageWidth; i+=2) 
27
    {
28
        if (i == 0) cmd.push(1);
29
        else		cmd.push(2);
30
        
31
        coord.push(i, quadratic_equation.fx_of(i));
32
    }
33
    
34
    graphics.clear();
35
    graphics.lineStyle(1);
36
    graphics.drawPath(cmd, coord);
37
}

Dan di sini adalah salah satu yang mengimplementasikan konsep matematika yang dijelaskan. C1 mengacu pada titik acak diposisikan di atas panggung.

1
2
private function recalculate_distance():void 
3
{
4
    var a:Number = m2.n11;	
5
    var b:Number = m2.n21;
6
    var c:Number = m2.n31;
7
    
8
    /*f(x) = Ax^3 + Bx^2 +Cx + D

9
     */
10
    var A:Number = 2*a*a
11
    var B:Number = 3*b*a
12
    var C:Number = b*b + 2*c*a - 2*a*c1.y +1
13
    var D:Number = c * b - b * c1.y - c1.x
14
    
15
    quartic_gradient = new EqCubic();
16
    quartic_gradient.define(A, B, C, D);
17
    quartic_gradient.calcRoots();
18
    
19
    roots = quartic_gradient.roots_R;
20
    var chosen:Number = roots[0];
21
    
22
    if (!isNaN(roots[1]) && !isNaN(roots[2])) {
23
        
24
        //calculate gradient and rate of gradient of all real roots

25
        var quartic_rate:Vector.<Number> = new Vector.<Number>;
26
        
27
        for (var i:int = 0; i < roots.length; i++) 
28
        {
29
            if (!isNaN(roots[i])) 	quartic_rate.push(quartic_gradient.diff1(roots[i]));
30
            else 					roots.splice(i, 1);
31
        }
32
        
33
        //select the root that will produce the shortest distance

34
        for (var j:int = 1; j < roots.length; j++) 
35
        {
36
            //the rate that corresponds with the root must be the highest positive value

37
            //because that will correspond with the minimum point

38
            if (quartic_rate[j] > quartic_rate[j - 1]) {
39
                chosen = roots[j];
40
            }
41
        }
42
        
43
        //position the extra roots in demo

44
        position_extras();
45
    }
46
    else {
47
        
48
        //remove the extra roots in demo

49
        kill_extras();
50
    }
51
    intersec_points[0].x = chosen
52
    intersec_points[0].y = quadratic_equation.fx_of(chosen);
53
}

Langkah 9: Contoh: deteksi tumbukan

Mari kita membuat menggunakan konsep ini mendeteksi tumpang tindih antara lingkaran dan kurva.

Idenya sederhana: jika jarak antara titik biru dan kuning titik titik kurang dari biru radius, kita memiliki tabrakan. Check out demo di bawah ini. Item interaktif adalah titik-titik merah (untuk mengontrol kurva) dan titik biru. Jika titik biru bertabrakan dengan kurva, itu akan memudar sedikit.


Langkah 10: ActionScript implementasi

Nah, kode cukup sederhana. Memeriksa sumber penuh di CollisionDetection.as.

1
2
graphics.moveTo(intersec_points[0].x, intersec_points[0].y);
3
graphics.lineTo(c1.x, c1.y);
4
5
var distance:Number= Math2.Pythagoras(
6
    intersec_points[0].x, 
7
    intersec_points[0].y, 
8
    c1.x, 
9
    c1.y)
10
11
if (distance < c1.radius)  c1.alpha = 0.5;
12
else                       c1.alpha = 1.0;
13
14
t.text = distance.toPrecision(3);

Langkah 11: Memantul dari kurva

Jadi sekarang bahwa kita tahu kapan akan terjadi tabrakan, mari kita coba untuk program beberapa tanggapan tabrakan. Bagaimana memantul dari permukaan? Periksa Flash presentasi di bawah ini.

Anda dapat melihat kapal (bentuk segitiga), dikelilingi oleh lingkaran (tembus biru). Setelah lingkaran bertabrakan dengan kurva, kapal akan memantul dari permukaan.


Langkah 12: Mengendalikan kapal

Berikut ini adalah ActionScript untuk mengontrol kapal.

1
2
public function CollisionDetection2() 
3
{
4
    /**

5
     * Instantiation of ship & its blue-ish circular area

6
     */
7
    ship = new Triangle();	addChild(ship);
8
    ship.x = Math.random() * stage.stageWidth;
9
    ship.y = stage.stageHeight * 0.8;
10
    
11
    c1 = new Circle(0x0000ff, 15);	addChild(c1);
12
    c1.alpha = 0.2;
13
    
14
    /**

15
     * Ship's velocity

16
     */
17
    velo = new Vector2D(0, -1);
18
    updateShip();
19
    
20
    stage.addEventListener(KeyboardEvent.KEY_DOWN, handleKey);
21
    stage.addEventListener(KeyboardEvent.KEY_UP, handleKey);
22
    stage.addEventListener(Event.EXIT_FRAME, handleEnterFrame);
23
    
24
    /**

25
     * The curve and the calculations

26
     */
27
    quadratic_equation = new EqQuadratic();
28
    
29
    curve_points = new Vector.<Circle>;
30
    populate(curve_points, 0xff0000, 3);
31
    
32
    intersec_points = new Vector.<Circle>;
33
    populate(intersec_points, 0xffff00, 3, false);
34
    
35
    redraw_quadratic_curve();
36
}
37
38
private function handleKey(e:KeyboardEvent):void 
39
{
40
    if (e.type == "keyDown") {
41
        if (e.keyCode == Keyboard.UP) isUp = true;
42
        else if (e.keyCode == Keyboard.DOWN) isDown = true;
43
        if (e.keyCode == Keyboard.LEFT) isLeft = true;
44
        else if (e.keyCode == Keyboard.RIGHT) isRight = true;
45
    }
46
    if (e.type == "keyUp") {
47
        if (e.keyCode == Keyboard.UP) isUp = false;
48
        else if (e.keyCode == Keyboard.DOWN) isDown = false;
49
        if (e.keyCode == Keyboard.LEFT) isLeft = false;
50
        else if (e.keyCode == Keyboard.RIGHT) isRight = false;
51
    }
52
}
53
54
private function handleEnterFrame(e:Event):void 
55
{
56
    /**

57
     * Control the magnitude

58
     */
59
    if (isUp) 		velo.setMagnitude(Math.min(velo.getMagnitude()+0.2, 3));
60
    else if(isDown)	velo.setMagnitude(Math.max(velo.getMagnitude()-0.2, 1));
61
    
62
    /**

63
     * Control the direction

64
     */
65
    if (isRight) velo.setAngle(velo.getAngle() + 0.03);
66
    else if (isLeft) velo.setAngle(velo.getAngle() - 0.03);
67
    
68
    recalculate_distance();
69
    
70
    if (distance < c1.radius) bounce();
71
    updateShip();
72
}
73
74
/**

75
 * Update ship's position, orientation and it's area (the blue-ish circle)

76
 */
77
private function updateShip():void {
78
    ship.x += velo.x;
79
    ship.y += velo.y;
80
    ship.rotation = Math2.degreeOf(velo.getAngle());
81
    
82
    c1.x = ship.x; 
83
    c1.y = ship.y;
84
    
85
    if (ship.x > stage.stageWidth || ship.x < 0) velo.x *= -1;
86
    if (ship.y > stage.stageHeight || ship.y < 0) velo.y *= -1;
87
}

Anda dapat melihat bahwa keyboard kontrol memperbarui bendera untuk menunjukkan apakah kiri, atas, kanan, atau tombol yang ditekan. Bendera ini akan ditangkap oleh enterframe event handler dan memperbarui besarnya dan arah kapal.


Langkah 13: Menghitung vektor refleksi

Aku sudah tertutup perhitungan vektor vektor refleksi di posting ini. Di sini, saya hanya akan mencakup bagaimana untuk mendapatkan vektor normal dari gradien.

\[
\frac{DF(x)} {dx} = gradient\\
gradien line\ = \frac {y} {x} \\
Assume\ gradient=0.5\\
y = 0.5\\
x = 1\\
Vector\ of\ left\ normal =
\begin{bmatrix}-1 \\0.5\end{bmatrix}\\
Vector\ of\ right\ normal =
\begin{bmatrix}1 \\-0.5\end{bmatrix}
\]


Langkah 14: ActionScript implementasi

Jadi ActionScript di bawah ini akan menerapkan konsep matematika yang dijelaskan di langkah sebelumnya. Periksa baris yang disorot:

1
2
private function bounce():void 
3
{
4
    var gradient:Number = quadratic_equation.diff1(intersec_points[0].x);
5
    var grad_vec:Vector2D = new Vector2D(1, gradient);
6
    
7
    var left_norm:Vector2D = grad_vec.getNormal(false);
8
    var right_norm:Vector2D = grad_vec.getNormal();
9
    var chosen_vec:Vector2D;
10
    
11
    if (velo.dotProduct(left_norm) > 0) chosen_vec = left_norm
12
    else 								chosen_vec = right_norm
13
        
14
    var chosen_unit:Vector2D = chosen_vec.normalise();
15
    var proj:Number = velo.dotProduct(chosen_unit);
16
    
17
    chosen_unit.scale(-2*proj);
18
    
19
    velo = velo.add(chosen_unit);
20
}

Kesimpulan

Yah, terima kasih untuk waktu Anda! Jika Anda telah menemukan ini berguna atau memiliki pertanyaan, meninggalkan beberapa komentar.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.