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

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

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

კომპიუტერული პროგრამირება

კურსი: კომპიუტერული პროგრამირება > თემა 5

გაკვეთილი 8: ნაწილაკთა სისტემები

ნაწილაკთა ტიპები

ახლა გამოვიყენებთ ობიექტზე ორიენტირებული პროგრამირების მაღალი დონის ტექნიკებს, როგორიცაა მემკვიდრეობითობა, ასე რომ, შეიძლება, გამოგადგეთ "მემკვიდრეობითობის" გადახედვა JS-ის შესავლის კურსში და შემდეგ დაბრუნდით. არ ინერვიულოთ, ჩვენ დაგელოდებით!
კარგად იცით, როგორ მუშაობს მემკვიდრეობითობა? კარგია, რადგან ჩვენ გამოვიყენებთ მემკვიდრეობითობას სხვადასხვა ტიპის Particle ქვეობიექტის გასაკეთებლად, რომლებიც დიდი დოზით იზიარებენ ფუნქციონალობას, მაგრამ ასევე მნიშვნელოვნად განსხვავდებიან.
განვიხილოთ გამარტივებული Particle-ის იმპლემენტაცია:
var Particle = function(position) {
  this.acceleration = new PVector(0, 0{,}05);
  this.velocity = new PVector(random(-1, 1), random(-1, 0));
  this.position = position.get();
};

Particle.prototype.run = function() {
  this.update();
  this.display();
};

Particle.prototype.update = function(){
  this.velocity.add(this.acceleration);
  this.position.add(this.velocity);
};

Particle.prototype.display = function() {
  fill(127, 127, 127);
  ellipse(this.position.x, this.position.y, 12, 12);
};
ახლა, Particle-ზე დაყრდნობით ვქმნით ობიექტის ახალ ტიპს, რომელსაც დავარქმევთ Confetti-ს. დავიწყებთ კონსტრუქტორი ფუნქციით, რომელიც იღებს იმავე რაოდენობის არგუმენტებს და, უბრალოდ, იძახებს Particle კონტსრუქტორს და გადასცემს მათ:
var Confetti = function(position) {
  Particle.call(this, position);
};
ახლა კი, ჩვენმა Confetti ობიექტებმა რომ გაიზიარონ იგივე მეთოდები, რომლებიც Particle ობიექტებს აქვთ, უნდა მივუთითოთ, რომ საჭიროა, მათი პროტოტიპი Particle პროტოტიპზე იყოს დაფუძნებული:
Confetti.prototype = Object.create(Particle.prototype);
Confetti.prototype.constructor = Confetti;
ამ მომენტისთვის გვაქვს Confetti ობიექტები, რომლებიც ზუსტად ისევე მოქმედებენ, როგორც Particle ობიექტები. მემკვიდრეობითობის იდეა არ არის დუბლიკატების შექმნა, მისი იდეაა ახალი ობიექტების შექმნა, რომლებიც დიდი დოზით იზიარებენ ფუნქციონალს, მაგრამ, აგრეთვე, რაღაცით განსხვავდებიან. ასე რომ, რით არის Confetti ობიექტი განსხვავებული? მხოლოდ სახელითაც კი ჩანს, რომ განსხვავებულად უნდა გამოიყურებოდეს. ჩვენი Particle ობიექტები არის ელიფსები, მაგრამ კონფეტი ხშირად არის კვადრატულად ამოჭრილი პატარა ფურცელი, ასე რომ, უნდა შევცვალოთ display მეთოდი და ისინი ვაჩვენოთ მართკუთხედებად:
Confetti.prototype.display = function(){
  rectMode(CENTER);
  fill(0, 0, 255, this.timeToLive);
  stroke(0, 0, 0, this.timeToLive);
  strokeWeight(2);
  rect(0, 0, 12, 12);
};
აი, პროგრამა ერთი Particle ობიექტის ნიმუშით და ერთი Confetti ობიექტის ნიმუშით. აღვნიშნოთ, რომ ისინი იქცევიან ერთნაირად, მაგრამ განსხვავდებიან ვიზუალურად:

მობრუნების დამატება

მოდით, ცოტა გავართულოთ. ვთქვათ, გვინდა, რომ Confetti ნაწილაკმა იტრიალოს ჰაერში ფრენისას. ცხადია, შეგვიძლია, შევქმნათ მოდელი კუთხური სიჩქარისა და აჩქარებისათვის, როგორც ეს რხევის სექციაში ვქენით. ამის ნაცვლად ვცდით სწრაფ და უხეშ ამოხსნას.
ვიცით, რომ ნაწილაკს გააჩნია x კოორდინატი სადღაც 0-სა და ფანჯრის სიგანეს შორის. ვთქვათ, რომ, თუ ნაწილაკის x კოორდინატი 0-ის ტოლია, მისი მობრუნება იყოს 0; როცა მისი x კოორდინატი სიგანის ტოლია, მისი მობრუნება იყოს TWO_PI-ის ტოლი. გეცნობათ? როდესაც გვაქვს ერთი მნიშვნელობა ერთი განსაზღვრის არით, რომლის სხვა განსაზღვრის არეზე ასახვა გვინდა, შეგვიძლია, გამოვიყენოთ ProcessingJS-ის map() ფუნქცია ახალი მნიშვნელობის ადვილად გამოსათვლელად.
var theta = map(this.position.x, 0, width, 0, TWO_PI);
და, მხოლოდ დამატებითი ხიბლის შესაძენად, შეგვიძლია, კუთხის დიაპაზონი ავსახოთ 0-იდან TWO_PI*2-მდე. მოდით, შევხედოთ, როგორ ჯდება ეს კოდი display() მეთოდში.
Confetti.prototype.display = function(){
  rectMode(CENTER);
  fill(0, 0, 255);
  stroke(0, 0, 0);
  strokeWeight(2);
  pushMatrix();
  translate(this.position.x, this.position.y);
  var theta = map(this.position.x, 0, width, 0, TWO_PI * 2);
  rotate(theta);
  rect(0, 0, 12, 12);
  popMatrix();
};
აი, როგორ გამოიყურება ის — გადატვირთეთ რამდენჯერმე, რათა ნახოთ მობრუნების ეფექტი:
აგრეთვე შეგვეძლო, theta (თეტა) დაგვეფუძნებინა y მდებარეობაზე, რასაც ოდნავ განსხვავებული ეფექტი აქვს. რატომ ხდება ასე? ნაწილაკს აქვს არანულოვანი მუდმივი აჩქარება y მიმართულებით, რაც ნიშნავს, რომ y სიჩქარე არის დროის წრფივი ფუნქცია, y მდებარეობა კი — დროის პარაბოლური (კვადრატული) ფუნქცია. შეგიძლიათ, ეს ქვემოთ მოცემული გრაფიკებზე ნახოთ (რომლებიც დაგენერირებულია ზემოთ მოცემული პროგრამის მიხედვით):
ეს ნიშნავს, რომ თუ კონფეტის (კუთხით) მობრუნებას დავაფუძნებთ y მდებარეობაზე, მაშინ მობრუნებაც პარაბოლური იქნება. ეს არ იქნება ფიზიკურად ძალიან ზუსტი, რადგან კონფეტის ტრიალი ჰაერში საკმაოდ ჩახლართულია, მაგრამ სცადეთ ეს თქვენით და ნახეთ, რამდენად რეალურად გამოიყურება! შეგიძლიათ, მოიფიქროთ სხვა ფუნქციები, რომლებიც კიდევ უფრო რეალურად გამოიყურება?

მრავალფეროვანი ნაწილაკების სისტემა

ახლა გვინდა, რომ შეგვეძლოს, შევქმნათ ბევრი Particle ობიექტი და ბევრი Confetti ობიექტი. ამისთვის გავაკეთეთ ParticleSystem ობიექტი. იქნებ შეგვიძლია, გავაფართოვოთ ის ისე, რომ Confetti ობიექტებისთვის თვალყურის დევნაც შევძლოთ? აი, ამის გაკეთების ერთ-ერთი გზა — ვაკოპირებთ იმას, რაც Particle ობიექტებისთვის გავაკეთეთ:
var ParticleSystem = function(position) {
  this.origin = position;
  this.particles = [];
  this.confettis = [];
};

ParticleSystem.prototype.addParticle = function() {
    this.particles.push(new Particle(this.origin));
    this.confettis.push(new Confetti(this.origin));
};

ParticleSystem.prototype.run = function(){
  for (var i = this.particles.length-1; i >= 0; i--) {
    var p = this.particles[i];
    p.run();
  }
for (var i = this.confettis.length-1; i >= 0; i--) {
    var p = this.confettis[i]; p.run();
  }
};
აღვნიშნოთ, რომ გვაქვს ორი განსხვავებული მასივი, ერთი ნაწილაკებისათვის, მეორე კი — კონფეტისთვის. ყოველ ჯერზე, როცა ნაწილაკების მასივს რაიმეს ვუკეთებთ, ეს კონფეტის მასივსაც უნდა გავუკეთოთ! ეს გამაღიზიანებელია, რადგან ეს ნიშნავს, რომ ორჯერ უფრო მეტი კოდი უნდა დავწეროთ და თუ რაიმეს შევცვლით, ეს ორ ადგილას უნდა შევცვალოთ. შეგვიძლია, ეს გამეორება თავიდან ავირიდოთ, რადგან JavaScript-ში მასივებში სხვადასხვა ტიპის ობიექტების შენახვააა შესაძლებელი და, ვინაიდან ჩვენს ობიექტებს ერთი და იგივე ინტერფეისი აქვთ, ვიძახებთ run() მეთოდს და ობიექტების ორივე ტიპი განსაზღვრავს ამ ინტერფეისს. ასე რომ, დავუბრუნდებით მხოლოდ ერთი მასივის შენახვას, შემთხვევითად შევარჩევთ, რა ტიპის ნაწილაკის ობიექტი დავამატოთ, და დავუბრუნდებით ერთი მასივის გადაყოლას. ეს გაცილებით უფრო მარტივი ცვლილებაა — მხოლოდ addParticle მეთოდის შეცვლა გვიწევს:
var ParticleSystem = function(position) {
  this.origin = position;
  this.particles = [];
};

ParticleSystem.prototype.addParticle = function() {
  var r = random(1);
  if (r < 0{,}5) {
    this.particles.push(new Particle(this.origin));
  } else {
    this.particles.push(new Confetti(this.origin));
  }
};

ParticleSystem.prototype.run = function(){
  for (var i = this.particles.length-1; i >= 0; i--) {
    var p = this.particles[i];
    p.run();
    if (p.isDead()) {
      this.particles.splice(i, 1);
    }
  }
};
ახლა ყველაფერი მწყობრშია!

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

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