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

თუ ვებფილტრს იყენებთ, დარწმუნდით, რომ *.kastatic.org და *.kasandbox.org დომენები არ არის დაბლოკილი.

ძირითადი მასალა

ვექტორების მოძრაობა

ამ ვექტორების მათემატიკის ამბები ისეთი რამ ჩანს, რაც უნდა ვიცოდეთ, მაგრამ რატომ? როგორ დაგვეხმარება ეს კოდის დაწერაში? სიმართლე ისაა, რომ გვჭირდება პრაქტიკა. დრო დაგვჭირდება იმისთვის, რომ სრული სიამოვნება მივიღოთ PVector კლასის გამოყენებით.
ეს ხშირი შემთხვევაა ახალი მონაცემთა სტრუქტურის სწავლისას. მაგალითად, როცა პირველად სწავლობთ მასივის შესახებ, გეჩვენებათ, რომ მასივის გამოყენება ბევრად მეტ ძალისხმევას მოითხოვს, ვიდრე რამდენიმე ცვლადის გამოყენება სხვადასხვა რამისთვის. მაგრამ ეს გეგმა მალევე ვარდება, როდესაც გჭირდებათ 100, 1 000 ან 10 000 რამისთვის ცვლადების გამოყენება.
იგივე შეიძლება ითქვას PVector-ზე. ის, რაც ახლა დიდ სამუშაოდ გეჩვენებათ, შედეგს გამოიღებს მომავალში და ეს შედეგი საკმაოდ დიდი იქნება. დიდხანს მოცდაც კი არ მოგიწევთ, რადგან თქვენს ჯილდოს შემდეგ თავში მიიღებთ.

სიჩქარე

მიუხედავად ამისა, ახლა გვსურს სიმარტივეზე გავამახვილოთ ყურადღება. რას ნიშნავს მოძრაობის დაპროგრამება ვექტორების გამოყენებით? ამის დასაწყისი ვნახეთ მხტუნავი ბურთის მაგალითში. ობიექტს ეკრანზე აქვს მდებარეობა (სადაც ის არის დროის ყოველ მოცემულ მომენტში), აგრეთვე აქვს სიჩქარე (ინსტრუქციები, როგორ უნდა გადაადგილდეს დროის ერთი მომენტიდან მეორეში). სიჩქარე ემატება მდებარეობას:
position.add(velocity);
და შემდეგ ვხატავთ ობიექტს ამ ადგილმდებარეობაზე:
ellipse(position.x, position.y, 16, 16);
ეს არის მოძრაობა 101:
  • მდებარეობას ვუმატებთ სიჩქარეს
  • ვხატავთ ობიექტს ამ ადგილმდებარეობაზე
მხტუნავი ბურთის მაგალითში მთელი ეს კოდი მოხდა ProcessingJS-ის draw ფუნქციაში. ახლა გვინდა, მთელ ამ მოძრაობის ლოგიკას მოვუყაროთ თავი ობიექტში. ამ გზით შეგვიძლია, შევქმნათ საფუძველი ჩვენს ProcessingJS-ის ყველა პროგრამაში მოძრავი ობიექტების დაპროგრამებისთვის.
ამ შემთხვევაში შევქმნით სტანდარტულ Mover (მოძრავ) ობიექტს, რომელიც აღწერს ნივთს (ან არსებას), რომელიც ეკრანის ირგვლივ მოძრაობს. შესაბამისად, უნდა გავითვალისწინოთ 2 კითხვა:
  • რა მონაცემები აქვს მოძრავს (mover-ს)?
  • რა ფუნქციონალი აქვს მოძრავს?
ჩვენი „მოძრაობა 101-ის“ ალგორითმი პასუხს გვცემს ამ კითხვებზე. Mover ობიექტს აქვს მონაცემთა 2 ნაწილი: position (ადგილმდებარეობა) და velocity (სიჩქარე), ორივე მათგანი PVector ობიექტია. შეგვიძლია, დავიწყოთ კონსტრუქტორი ფუნქციის დაწერით, რომელიც ინიციალიზაციას უკეთებს ამ თვისებებს ადეკვატურ შემთხვევით ცვლადებზე:
var Mover = function() {
  this.position = new PVector(random(width), random(height));
  this.velocity = new PVector(random(-2, 2), random(-2, 2));
};
მისი ფუნქციონალობა ასეთივე მარტივია. მოძრავი უნდა მოძრაობდეს და მას უნდა ვხედავდეთ. ამ მოთხოვნებს იმპლემენტაციას გავუკეთებთ მეთოდებად, რომელთაც დავარქმევთ 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 ობიექტის შიდა ნაწილს მისი მდებარეობისა და მოძრაობისათვის თვალყურის სადევნებლად. ეს არის დიდებული პირველი ნაბიჯი და იმსახურებს მსუბუქ აპლოდისმენტებს. დიდი ოვაციებისა და ფანების კივილისათვის კი გვჭირდება კიდევ ერთი მეტ-ნაკლებად დიდი ნაბიჯის გადადგმა წინ. „მოძრაობა 101-ის“ მაგალითის ყურება ცოტათი მოსაწყენია — წრე არასდროს ჩქარდება, არასდროს ნელდება და არასდროს უხვევს. უფრო საინტერესო მოძრაობისათვის — ისეთი მოძრაობისათვის, როგორსაც რეალურ ცხოვრებაში ვხვდებით — კიდევ ერთი PVector უნდა დავამოტოთ ჩვენს Mover ობიექტს — აჩქარება.
აჩქარების მკაცრი განსაზღვრება, რომელსაც აქ ვიყენებთ, ასეთია: სიჩქარის ცვლილების სიჩქარე. დავფიქრდეთ ამ განსაზღვრებაზე. ეს ახალი კონცეფციაა? არა. სიჩქარე არის განსაზღვრული მდებარეობის ცვლილების სიჩქარე. აზრობრივად, ჩვენ ვქმნით ორნაბიჯიან ეფექტს: აჩქარება ცვლის სიჩქარეს, რომელიც ცვლის მდებარეობას (ეს იდეა უფრო მნიშვნელოვანი გახდება მომავალში, როცა ვნახავთ, როგორ ცვლიან ძალები აჩქარებას, რომელიც ცვლის სიჩქარეს, ის კი — მდებარეობას). კოდში ეს ასე გამოიყურება:
velocity.add(acceleration);
position.add(velocity);
როგორც დავალება, მოდით, ამიერიდან ჩვენი თავისთვის წესი შევქმნათ. მოდით, ამ სახელმძღვანელოების ყველა დანარჩენი მაგალითი დავწეროთ სიჩქარისა და მდებარეობის ხელშეუხებლად (გარდა მათი ინიციალიზაციისა). სხვა სიტყვებით რომ ვთქვათ, მოძრაობის პროგრამირებისთვის ჩვენი მიზანი ახლა არის შემდეგი: მოვიგონოთ ალგორითმი აჩქარების გამოსათვლელად და ნაკადის დაშვების ეფექტს ვაცადოთ ჯადოქრობა (სინამდვილეში, ამ წესის დასარღვევად მიზეზებს გამონახავთ, მაგრამ ჩვენი მოძრაობის ალგორითმის უკან არსებული იდეების ილუსტრაცია მნიშვნელოვანია). ასე რომ, უნდა მოვიფიქროთ რაღაც გზები აჩქარების გამოსათვლელად:
  1. მუდმივი აჩქარება
  2. სრულიად შემთხვევითი აჩქარება
  3. აჩქარება მაუსისკენ
ალგორითმი #1, მუდმივი აჩქარება, გამორჩეულად საინტერესო არ არის, მაგრამ ის ყველაზე მარტივია და დაგვეხმარება, დავიწყოთ აჩქარების ჩვენს კოდში შემოტანა.
პირველ ყოვლისა, უნდა დავამატოთ ახალი PVector თვისება Mover კონსტრუქტორს აჩქარების წარმოსადგენად. მას ინიციალიზაციას გავუკეთებთ (0,001,0,01)-ზე და ამ მნიშვნელობაზე დავტოვებთ სამუდამოდ, რადგან ჩვენი მიმდინარე ალგორითმი არის მუდმივი აჩქარება. შეიძლება, ფიქრობთ, „ღმერთო, ეს მნიშვნელობები ძალიან მცირეა!“ ეს სიმართლეა, ისინი საკმაოდ პატარებია. მნიშვნელოვანია, გავიაზროთ, რომ ჩვენი აჩქარების მნიშვნელობები (მათ პიქსელებში ვზომავთ) გაიზრდება სიჩქარეში დროის განმავლობაში, დაახლოებით 30-ჯერ წამში (ეს დამოკიდებულია ჩვენი ჩანახატის კადრის სიხშირეზე). შესაბამისად, ვექტორის სიგრძის ადეკვატურ დიაპაზონში დასატოვებლად ჩვენი აჩქარების მნიშვნელობები დასაწყისშიც და შემდეგაც საკმაოდ პატარა უნდა იყოს.
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);  
};
ვინაიდან გამუდმებით ვაჩქარებთ სიჩქარეს, არსებობს საფრთხე, რომ ჩვენი სიჩქარის მნიშვნელობები ძალიან დიდი გახდება, თუკი პროგრამას საკმარისად დიდხანს დავტოვებთ გაშვებულს. გვინდა, რომ სიჩქარეს შევუზღუდოთ მაქსიმალური მნიშვნელობა. ამის გაკეთება შეგვიძლია PVector limit მეთოდის გამოყენებით, რომელიც ვექტორს შეზღუდავს მოცემულ სიგრძეზე.
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);  
};
ვინაიდან შემთხვევითი ვექტორი ნორმალიზებულია, მისი სკალირება 2 განსხვავებული ტექნიკით შეგვიძლია:
  1. აჩქარების სკალირება მუდმივ მნიშვნელობაზე:
    acceleration = PVector.random2D();
    acceleration.mult(0{,}5);
    
  1. აჩქარების სკალირება შემთხვევით მნიშვნელობაზე:
    acceleration = PVector.random2D();
    acceleration.mult(random(2));
    
შესაძლოა, ეს ზედმეტად ცხად რამედ მოგეჩვენოთ, მაგრამ მნიშვნელოვანია, გავიგოთ, რომ აჩქარება არ ნიშნავს მოძრავი ობიექტის მარტოოდენ სიჩქარის მომატებას ან სიჩქარის შენელებას, ის აგრეთვე ნიშნავს ნებისმიერ ცვლილებას სიჩქარის სიდიდეში ან მიმართულებაში. აჩქარება გამოიყენება ობიექტის სამართავად და ამას კიდევ ბევრჯერ ვნახავთ მომდევნო თავებში, როცა დავიწყებთ ისეთი ობიექტების კეთებას, რომლებიც წყვეტენ, როგორ იმოძრაონ ეკრანზე.
ეს „ბუნებრივი სიმულაციების" კურსი ეფუძნება დანიელ შიფმენის წიგნს "კოდის ბუნებას", ის გამოყენებულია ლიცენზიით Creative Commons Attribution-NonCommercial 3,0 Unported License.

გსურთ, შეუერთდეთ დისკუსიას?

პოსტები ჯერ არ არის.
გესმით ინგლისური? დააწკაპუნეთ აქ და გაეცანით განხილვას ხანის აკადემიის ინგლისურენოვან გვერდზე.