If you're seeing this message, it means we're having trouble loading external resources on our website.

Եթե գտնվում ես վեբ զտիչի հետևում, խնդրում ենք համոզվել, որ *.kastatic.org և *.kasandbox.org տիրույթները հանված են արգելափակումից։

Հիմնական նյութ

Վեկտորի շարժում

Տպավորություն է, որ վեկտորների մաթետիկան կարևոր է իմանալ, բայց ինչո՞ւ։ Ինչպե՞ս է դա մեզ օգնելու կոդ գրելիս։ Հասկանալու համար մեզ մի փոքր համբերություն է պետք։ PVector դասի կիրառման հրաշալի հնարավորությունները մենք ժամանակի ընթացքում ենք բացահայտելու։
Իրականում նոր տվյալների կառուցվածքի մասին սովորելիս սա տարածված պատահույթ է։ Օրինակ, երբ զանգվածների մասին նոր ես սովորում, թվում է, թե զանգված ստեղծելու փոխարեն ավելի հեշտ է պարզապես մի քանի փոփոխական պահել, բայց այդ մոտեցումը դադարում է հնարավոր տարբերակ լինել, երբ խոսում ենք 100, 1000 կամ 10000 փոփոխականի մասին։
Նույն կերպ՝ սկզբում կթվա, որ PVector-ը անիմաստ շատ աշխատանք է, սակայն դրա օգուտն ընդամենը հաջորդ գլխում արդեն քեզ համար պարզ կդառնա։

Արագություն

Այնուամենայնիվ, առայժմ պարզության վրա կենտրոնանանք։ Ի՞նչ է նշանակում վեկտորներով շարժում ծրագրավորել։ Այն մի փոքր քննարկել ենք ցատկող գնդակի օրինակով։ Էկրանի վրայի օբյեկտն ունի դիրք՝ իր գտնվելու վայրի կոորդինատները, և արագությունը՝ ժամանակի տվյալ պահին շարժման վերաբերյալ հրահանգ։ Արագությունը գումարվում է դիրքին.
position.add(velocity);
Դրանից հետո օբյեկտը պատկերում ենք նոր դիրքում.
ellipse(position.x, position.y, 16, 16);
Սա շարժման պարզագույն տարբերակն է.
  • Արագությունը գումարիր դիրքին.
  • օբյեկտը պատկերիր այդ դիրքում:
Ցատկող գնդակի օրինակում այդ ամենը գրված էր ProcessingJS-ի draw ֆունկցիայում։ Այժմ ուզում ենք որևէ բան շարժելու տրամաբանությունը հենց օբյեկտում գրել։ Դա կարող է ProcessingJS-ի հետագա ծրագրերում շարժվող իրեր ծրագրավորելու համար հիմք հանդիսանալ։
Ստեղծելու ենք ընդհանրական Mover օբյեկտ, որը կնկարագրի էկրանի վրա շարժվող ցանկացած իր։ Դրա համար պետք է փորձենք պատասխանել հետևյալ հարցերին.
  • Ի՞նչ տեղեկություն է անհրաժեշտ այդ օբյեկտին։
  • Ի՞նչ գործառույթներ ունի այն։
Այս հարցերի պատասխանները կարելի է գտնել շարժման պարզագույն ալգորիթմում։ Mover-ն ունի երկու տվյալ՝ position և velocity, որոնցից երկուսն էլ PVector օբյեկտներ են։ Սկզբի համար կարող ենք կառուցող ֆունկցիա գրել, որն այս հատկություններին հարմար պատահական արժեքներ է փոխանցում։
var Mover = function() {
  this.position = new PVector(random(width), random(height));
  this.velocity = new PVector(random(-2, 2), random(-2, 2));
};
Գործառույթներն էլ են բավականին պարզ։ Mover-ը պետք է շարժվի և տեսանելի լինի։ Այս գործառույթները կարող ենք կիրառել update() և display() կոչվող մեթոդներում։ Շարժման տրամաբանությունը կգրենք update()-ում, իսկ օբյեկտը պատկերելունը՝ display()-ում։
Mover.prototype.update = function() {
  this.position.add(this.velocity);
};

Mover.prototype.display = function() {
  stroke(0);
  strokeWeight(2);
  fill(127);
  ellipse(this.position.x, this.position.y, 48, 48);
};
Եթե օբյեկտային կողմնորոշվածությամբ ծրագրավորումը քեզ համար նորություն է, հավանական է, որ մի փոքր խճճվել ես։ Չէ՞ որ գլխի սկզբում PVector-ն էինք քննարկում՝ ասելով, որ PVector-ը դիրքի ու արագության օբյեկտները ստանալու կաղապար է։ Եթե այդպես է, այն ի՞նչ գործ ունի այլ օբյեկտի մեջ, օրինակ՝ Mover-ի։ Իրականում սա շատ ընդունված մոտեցում է։ Հիշիր, որ օբյեկտը ընդամենը տվյալ պարունակող ու ինչ-որ գործառույթներ ունեցող բան է։ Այդ տվյալները կարող են թվեր, տողայիններ, զանգվածներ և այլ օբյեկտներ լինել։ Այս դասընթացի ընթացքում այս երևույթը շատ ես տեսնելու։ Օրինակ՝ «Մասնիկներ» հոդվածում գրելու ենք մասնիկների համակարգ նկարագրող օբյեկտ։ ParticleSystem օբյեկտն ունենալու է Particle օբյեկտներ պարունակող զանգված, իսկ յուրաքանչյուր Particle օբյեկտ ունենալու է բազմաթիվ PVector օբյեկտներ։
Mover օբյեկտն ամբողջացնելու համար գրենք ֆունկցիա, որն ասում է՝ ինչ անել, երբ օբյեկտը հասնում է պատուհանի ծայրերից մեկին։ Սկզբի համար կարող ենք պարզապես գրել, որ այն շարժումը շարունակի մյուս կողմից.
Mover.prototype.checkEdges = function() {

  if (this.position.x > width) {
    this.position.x = 0;
  } 
  else if (this.position.x < 0) {
    this.position.x = width;
  }

  if (this.position.y > height) {
    this.position.y = 0;
  } 
  else if (this.position.y < 0) {
    this.position.y = height;
  }
};
Քանի որ Mover օբյեկտն արդեն պատրաստ է, կարող ենք ծրագիրը դիտարկել։ Սկզբում պետք է հայտարարենք և ստեղծենք Mover-ի նոր օրինակ.
var mover = new Mover();
Հետո draw-ում պետք է համապատասխան ֆունկցիաները կանչենք.
draw = function() {
  background(255, 255, 255);

  mover.update();
  mover.checkEdges();
  mover.display(); 
};
Ահա ամբողջական օրինակը։ Կարող ես որոշ թվեր փոփոխել, կոդի որոշ հատվածներ մեկնաբանություններ դարձնել՝ կատարվածն ավելի լավ պատկերացնելու համար։

Արագացում

Այս պահին արդեն երկու բան բավականին լավ ենք ընկալել. 1) ինչ է PVector-ը, և 2) ինչպես ենք օբյեկտի ներսում PVector-ներ կիրառում՝ դիրքն ու շարժումը պահելու համար։ Սա շատ լավ սկիզբ է, և դու ծափահարությունների ես արժանի։ Սակայն հոտնկայս ծափահարությունների ու երկրպագուների արժանանալուց առաջ ևս մեկ քայլ պետք է կատարես։ Չէ՞ որ նախկին օրինակը նայելը բավականին ձանձրալի է. գնդակը երբեք չի արագանում, չի դանդաղում և չի պտտվում։ Ավելի հետաքրքիր ու իրական աշխարհն ավելի լավ նմանակող շարժում ստանալու համար Mover օբյեկտին է պետք ևս մեկ PVector ավելացնել՝ արագացում։
Արագացման՝ մեր կիրառած սահմանումը հետևյալն է. արագության փոփոխության արագությունը։ Մի պահ մտածենք այդ սահմանման մասին։ Արդյո՞ք դա նոր գաղափար է. այնքան էլ չէ։ Արագությունը սահմանվում է որպես դիրքի փոփոխության արագություն։ Ըստ էության, ստանում ենք դեպի ներքև փոխանցվող ազդեցություն։ Արագացումն ազդում է արագության, որն էլ իր հերթին ազդում է դիրքի վրա. նշենք, որ այս գաղափարն է՛լ ավելի կարևոր է հաջորդ գլխում, երբ կտեսնենք, թե ինչպես են ուժերն ազդում արագացման վրա, որն իր հերթին ազդում է արագության, սա էլ իր հերթին՝ դիրքի վրա։ Կոդը կարելի է գրել այսպես.
velocity.add(acceleration);
position.add(velocity);
Սրանից հետո կարող ենք որպես վարժություն փորձել անել հետևյալը։ Մնացած բոլոր հոդվածներում բոլոր օրինակների դիրքի ու արագության մասին ոչինչ չգրենք, բացի դրանք ստեղծելուց։ Այլ կերպ ասած, շարժում ծրագրավորելու մեր նոր նպատակը հետևյալն է. գտնել արագացումը հաշվելու ալգորիթմ ու մնացածն արդեն թողնել արագացման դեպի ներքև փոխանցվող ազդեցության վրա։ Իրականում ժամանակ առ ժամանակ այս սկզբունքից շեղվելու պատճառներ կլինեն, բայց այս մոտեցումը կօգնի շարժման ալգորիթմի սկզբունքները լիովին հասկանալ։ Հետևաբար, պետք է գտնենք արագացումը հաշվելու ձևեր.
  1. Հաստատուն արագացում
  2. Պատահական արագացում
  3. Դեպի մկնիկ արագացում
Ալգորիթմ #1-ը՝ հաստատուն արագացումը, առանձնապես հետաքրքիր չէ, սակայն դրա պարզությունը մեզ կօգնի արագացումը ներառել կոդի մեջ։
Սկզբի համար պետք է Mover օբյեկտում ևս մեկ PVector հատկություն գրել արագացման համար։ Դրան կփոխանցենք (0,001,0,01) արժեքը և չենք փոփոխի, քանի որ մեր ընթացիկ ալգորիթմը հաստատուն արագացումն է։ Միգուցե մտածես, որ այդ արժեքները շա՜տ փոքր են։ Իրականում ճիշտ ես, սակայն պետք է հաշվի առնենք, որ ընթացքում պիքսելով հաշված արագացման արժեքները արագության մեջ մոտավորապես վայրկյանը երեսուն անգամ գումարվելու են՝ կախված մեր կադրերի փոփոխման արագությունից։ Հետևաբար, արագության վեկտորի երկարությունը տրամաբանական սահմաններում պահելու համար արագացման արժեքները պետք է և՛ սկզբում, և՛ ընթացքում բավականին փոքր մնան։
var Mover = function() {
  this.position = new PVector(width/2,height/2);
  this.velocity = new PVector(0, 0);
  this.acceleration = new PVector(-0,001, 0,01);
};
Ուշադրություն դարձրու, որ արագության սկզբնական արժեքը 0 է, քանի որ գիտենք, որ արագացման շնորհիվ ծրագրի կատարման ընթացքում այն մեծանալու է։ Դա կկիրառենք update() մեթոդում։
Mover.prototype.update = function() {
  this.velocity.add(this.acceleration);
  this.position.add(this.velocity);  
};
Քանի որ արագությունն անընդհատ մեծացնում ենք, հավանական է, որ ծրագիրը երկար կատարելու դեպքում ինչ-որ պահից արագությունը չափազանց մեծ լինի։ Հետևաբար, պետք է արագությունը սահմանափակենք ինչ-որ մեծագույն արժեքով։ Դրա համար կարող ենք կիրառել PVectorlimit մեթոդը, որը սահմանափակում է վեկտորի երկարությունը։
Mover.prototype.update = function() {
  this.velocity.add(this.acceleration);
  this.velocity.limit(10);
  this.position.add(this.velocity);  
};
Սա նշանակում է՝
Որքա՞ն է վեկտորի երկարությունը։ Եթե 10-ից փոքր է, խնդիր չկա, թող մնա։ Եթե 10-ից մեծ է, դարձնել 10։
Դիտարկենք Mover օբյեկտում կատարվող փոփոխությունները, երբ այն պարունակում է acceleration և limit() հրամանները.
Այժմ անցնենք Ալգորիթմ #2-ին՝ պատահական արագացմանը։ Այս դեպքում արագացմանը օբյեկտի կառուցիչում արժեք տալու փոխարեն յուրաքանչյուր ցիկլում, այսինքն՝ ամեն անգամ update() կանչելիս արագացման համար նոր արժեք ենք ընտրելու։
Mover.prototype.update = function() {
  this.acceleration = PVector.random2D();
  this.velocity.add(this.acceleration);
  this.velocity.limit(10);
  this.position.add(this.velocity);  
};
Քանի որ պատահական վեկտորը նորմավորված է, կարող ենք դրա չափը երկու ձևով փոխել՝
  1. չափը փոխել հաստատուն թվով.
    acceleration = PVector.random2D();
    acceleration.mult(0,5);
    
  1. չափը փոխել պատահական թվով.
    acceleration = PVector.random2D();
    acceleration.mult(random(2));
    
Ինչքան էլ պարզ թվա, հարկ ենք համարում նշել, որ արագացումը միայն շարժվող մարմինն արագացնելուն կամ դանդաղեցնելուն չի վերաբերում. այն արագության ցանկացած փոփոխությանն է վերաբերում՝ լինի դա երկարության, թե ուղղության փոփոխություն։ Արագացումը կիրառվում է առարկաներն ուղղորդելու համար. այս փաստն ավելի պարզ կդիտարկես հետագա գլուխներում, երբ սկսենք էկրանում իրենց շարժման վերաբերյալ որոշումներ կայացնող օբյեկտներ ծրագրավորել։

«Բնական նմանակիչներ» դասընթացը ստեղծվել է Դանիել Շիֆմանի «Կոդի բնույթը» գրքի հիման վրա և կիրառվում է ըստ Creative Commons Attribution-NonCommercial 3,0 Unported License-ի։

Ուզո՞ւմ ես միանալ խոսակցությանը։

Առայժմ հրապարակումներ չկան։
Անգլերեն հասկանո՞ւմ ես: Սեղմիր այստեղ և ավելի շատ քննարկումներ կգտնես «Քան» ակադեմիայի անգլերեն կայքում: