თუ თქვენ ხედავთ ამ შეტყობინებას, ესე იგი საიტზე გარე რესურსების ჩატვირთვისას მოხდა შეფერხება.

If you're behind a web filter, please make sure that the domains *.kastatic.org and *.kasandbox.org are unblocked.

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

გრავიტაციული მიზიდულობა

ალბათ, ყველაზე ცნობილი ძალა არის გრავიტაცია. გრავიტაციაზე ფიქრისას ადამიანებს გვახსენდება ისააკ ნიუტონი, რომელსაც თავზე ვაშლი ეცემა. გრავიტაცია ნიშნავს, რომ საგნები ძირს ვარდება. მაგრამ ეს გრავიტაციის მხოლოდ ჩვენეული გამოცდილებაა. სიმართლე რომ ვთქვათ, როცა დედამიწა ექაჩება ვაშლს გრავიტაციის ძალის გამო, ამავდროულად ვაშლიც ექაჩება დედამიწას მისკენ. საქმე ისაა, რომ დედამიწა იმდენად დიდია, რომ ის ფარავს ამ პლანეტაზე მყოფი ყველა სხვა ობიექტის გრავიტაციის ყველა ინტერაქციას. მასის მქონე ყველა ობიექტი მოქმედებს გრავიტაციის ძალით ყველა სხვა ობიექტზე. ამ ძალების სიდიდის გამოსათვლელად არსებობს ფორმულა, რომელიც ქვედა დიაგრამაში არის მოცემული.
მოდით, განვიხილოთ ეს ფორმულა ცოტა უფრო დაწვრილებით.
  • F აღნიშნავს გრავიტაციის ძალას — ვექტორს, რომლის გამოთვლა და გადაცემა გვინდა ჩვენი applyForce() ფუნქციისთვის.
  • G არის გრავიტაციული მუდმივა, რომელიც, ჩვენს შემთხვევაში, უდრის 6,67428 x 10^-11 კუბურ მეტრს კილოგრამზე კვადრატულ წამში ( (მ^3)*(წმ^2)/კგ ). ეს ძალიან მნიშვნელოვანი რიცხვია, თუ თქვენი სახელია ისააკ ნიუტონი ან ალბერტ აინშტაინი. ეს არ არის მნიშვნელოვანი რიცხვი, თუ თქვენ ხართ ProcessingJS-ის პროგრამისტი. კიდევ ერთხელ აღვნიშნოთ, ეს არის მუდმივა, რომლის გამოყენებაც შეგვიძლია ჩვენს სამყაროში ძალების გასაძლიერებლად ან შესასუტებლად. მისი ერთისთვის გატოლება და შემდეგ იგნორირება არც ისე ცუდი არჩევანია.
  • m1 და m2 არის ობიექტების მასები 1 and 2. როგორც ნიუტონის მეორე კანონში ვნახეთ (F=MA), მასის იგნორირებაც შეგვიძლია. ეკრანზე გამოსახულ ფიგურებს ხომ რეალურად არ გააჩნიათ მასა. თუმცა, თუ ამ მნიშვნელობებს შევინახავთ, შეგვიძლია, შევქმნათ უფრო საინტერესო სიმულაციები, რომლებშიც „უფრო დიდი“ ობიექტები მოქმედებენ უფრო დიდი გრავიტაციის ძალით, ვიდრე პატარები.
  • r^ აღნიშნავს ერთეულოვან ვექტორს, რომელიც მიმართულია ობიექტი 1-იდან ობიექტ 2-ისკენ. როგორც ახლა ვნახავთ, ამ ვექტორის გამოთვლა შეგვიძლია ერთი ობიექტის ადგილმდებარეობისთვის მეორე ობიექტის ადგილმდებარეობის გამოკლებით.
  • r2 აღნიშნავს ამ 2 ობიექტს შორის მანძილის კვადრატს. მოდით, დავფიქრდეთ ამაზე. შევხედოთ ყველაფერს ფორმულაში — G, m1, m2 — რაც უფრო დიდია მისი მნიშვნელობა, მით უფრო მეტია ძალის სიდიდე. დიდი მასა, დიდი ძალა. დიდი G, დიდი ძალა. თუმცა გაყოფისას ამის საპირისპირო შედეგი გვაქვს. ძალის სიდიდე უკუპროპორციულია მანძილის კვადრატის. რაც უფრო შორსაა ობიექტი, მით უფრო სუსტია ძალა; რაც უფრო ახლოსაა, მით უფრო ძლიერია.
იმედია, ახლა ფორმულა უკეთ გვესმის. ჩვენ შევხედეთ დიაგრამას და ფორმულის ცალკეული კომპონენტები გამოვყავით. ახლა დროა, გავარკვიოთ, როგორ გადავთარგმნოთ მიღებული მათემატიკური შედეგები ProcessingJS-ის კოდში. გავაკეთოთ შემდეგი დაშვებები.
გვაქვს ორი ობიექტი და:
  1. ყოველ ობიექტს აქვს PVector ადგილმდებარეობა: location1 და location2.
  2. ყოველ ობიექტს აქვს რიცხობრივი მასა: mass1 და mass2.
  3. არსებობს რიცხობრივი ცვლადი G უნივერსალური გრავიტაციული მუდმივისთვის.
მოცემული დაშვებების მიხედვით გვინდა, გამოვთვალოთ PVector ძალა - გრავიტაციის ძალა. ამ გამოთვლას ორ ნაწილად დავყოფთ. ჯერ გამოვთვლით ძალის მიმართულებას r^ ზედა ფორმულაში, შემდეგ კი გამოვთვლით ძალის სიდიდეს მასებისა და მანძილის მიხედვით.
გახსოვთ, ობიექტს რომ მაუსის მიმართულებით ვაჩქარებდით? აქაც იმავე ლოგიკას გამოვიყენებთ.
ვექტორი არის ორ წერტილს შორის სხვაობა. ისეთი ვექტორის შესაქმნელად, რომელიც მიმართულია წრიდან მაუსისკენ, ჩვენ, უბრალოდ, გამოვაკელით ერთი წერტილი მეორეს:
var dir = PVector.sub(mouse, location);
ჩვენს შემთხვევაში მიზიდულობის ძალის მიმართულება, რომლითაც ობიექტი 1 მოქმედებს ობიექტ 2-ზე, უდრის:
var dir = PVector.sub(location1, location2);
არ დაგავიწყდეთ, რომ ვინაიდან გვინდა ერთეულოვანი ვექტორი — ვექტორი, რომელიც მხოლოდ მიმართულებას აღგვიწერს — დაგვჭირდება ვექტორის ნორმალიზაცია ადგილმდებარეობების გამოკლების შემდეგ:
dir.normalize();
კარგი, ჩვენ გავიგეთ ძალის მიმართულება. ახლა უნდა გამოვთვალოთ ვექტორის სიგრძე და ვექტორი შესაბამის რიცხვზე გავყოთ.
var m = (G * mass1 * mass2) / (distance * distance);
dir.mult(m);
ერთადერთი პრობლემა ისაა, რომ არ ვიცით მანძილი. G, mass1 და mass2 მოცემული გვქონდა, მაგრამ ზემოთ მოცემული კოდის ასამუშავებლად უნდა გამოვთვალოთ მანძილი. განა ახლახან არ შევქმენით ვექტორი, რომელიც ერთი ადგილმდებარეობიდან მეორისკენ არის მიმართული? ამ ვექტორის სიგრძე იგივე ამ ორ ობიექტს შორის მანძილი არ არის?
თუ დავამატებთ კოდის მხოლოდ ერთ ხაზს და დავიმახსოვრებთ ამ ვექტორის სიგრძეს მის ნორმალიზებამდე, მაშინ გვექნება მანძილიც.
// ვექტორი, რომელიც მიუთითებს ერთი ობიექტიდან მეორეზე
var force = PVector.sub(location1, location2);

// ამ ვექტორის სიგრძე (სიდიდე) არის მანძილი ორ ობიექტს შორის.
var distance = force.mag();

// გამოიყენეთ გრავიტაციის ფორმულა ძალის სიდიდის გამოსათვლელად.
var strength = (G * mass1 * mass2) / (distance * distance);

// გაუკეთეთ ნორმალიზება და სკალირება ვექტორს შესაფერის სიდიდეზე.
force.normalize();
force.mult(strength);
აღვნიშნოთ, რომ მე PVector “dir”-ს გადავარქვი სახელი და დავარქვი “force”, რადგან როდესაც გამოთვლებს დავასრულებთ, PVector, რომლითაც დავიწყეთ, გახდება ძალის ვექტორი, რომლის მიღებაც გვინდოდა.
ახლა, როცა მათემატიკისა და კოდის ნაწილს მოვრჩით მიმზიდველი ძალის (რომელიც გრავიტაციის იმიტაციას აკეთებს) გამოსათვლელად, ყურადღება უნდა გადავიტანოთ ამ ტექნიკის ProcessingJS-ის პროგრამის კონტექსტში გამოყენებაზე. ამ სექციაში ჩვენ ადრე შევქმენით მარტივი Mover ობიექტი — ობიექტი PVector-ის ადგილმდებარეობით, სიჩქარითა და აჩქარებით, აგრეთვე შევქმენითapplyForce(). ავიღოთ ეს კლასი და მასთან ერთად ჩავსვათ პროგრამაში:
  • ერთი Mover ობიექტი.
  • ერთი Attractor ობიექტი (ახალი ობიექტის ტიპი, რომელსაც ექნება ფიქსირებული ადგილმდებარეობა).
Mover (მოხეტიალე) ობიექტზე იმოქმედებს Attractor (მიმზიდველი) ობიექტისკენ მიმართული გრავიტაციული მიზიდულობა, როგორც ეს დიაგრამაშია ნაჩვენები.
შეგვიძლია, დავიწყოთ ახალი Attractor ობიექტის ძალიან მარტივად შექმნით — მივცეთ მას ადგილმდებარეობა და მასა, აგრეთვე მეთოდი მის ეკრანზე საჩვენებლად (მასა მივაბათ ზომას).
var Attractor = function() {
    this.position = new PVector(width/2, height/2);
    this.mass = 20;
    this.G = 1;
    this.dragOffset = new PVector(0, 0);
    this.dragging = false;
    this.rollover = false;
};

// ეკრანზე გამოტანის მეთოდი
Attractor.prototype.display = function() {
    ellipseMode(CENTER);
    strokeWeight(4);
    stroke(0);
    fill(175, 175, 175, 200);
    ellipse(this.position.x, this.position.y, this.mass*2, this.mass*2);
};
ამის განსაზღვრის შემდეგ შეგვიძლია, შევქმნათ Attractor ობიექტის ტიპის ნიმუში.
var mover = new Mover();
var attractor = new Attractor();

draw = function() {
    background(50, 50, 50);

    attractor.display();
    mover.update();
    mover.display();
};
ეს კარგი სტრუქტურაა: მთავარი პროგრამა Mover-ით და Attractor ობიექტით. ისღა დაგვრჩა, მივხვდეთ, თუ როგორ მივაზიდინოთ ერთ ობიექტს მეორე. როგორ ვალაპარაკოთ ერთმანეთთან ეს ორი ობიექტი?
ამის არქიტექტურულად გასაკეთებლად არსებობს მრავალი გზა. აქ მხოლოდ რამდენიმე ვარიანტია.
დავალებაფუნქცია
1. ფუნქცია, რომელიც იღებს Attractor-საც და Mover-საც:attraction(a, m);
2. მეთოდი Attractor ობიექტში, რომელიც იღებს Mover-ს:a.attract(m);
3. მეთოდი Mover ობიექტში, რომელიც იღებს Attractor-ს:mover.attractedTo(a);
4. მეთოდი Attractor ობიექტში, რომელიც იღებს Mover-ს და აბრუნებს PVector-ს, რომელიც არის მიზიდულობის ძალა. ეს მიზიდულობის ძალა შემდეგ გადაეცემა Mover-ის applyForce() მეთოდს.var f = a.calculateAttraction(m); mover.applyForce(f);
კარგია, შევხედოთ სხვადასხვა ვარიანტს ობიექტების ერთმანეთთან დასალაპარაკებლად და თქვენ, ალბათ, შეგიძლიათ თითოეული მათგანის უპირატესობებზე საუბარი. დავიწყოთ პირველის გამოტოვებით, რადგან ობიექტზე ორიენტირებული მიდგომა გაცილებით უკეთესი მიდგომაა, ვიდრე ფუნქცია, რომელიც არ არის დაკავშირებული არც Mover და არც Attractor ობიექტებთან. მე-2 და მე-3 ვარიანტებს შორის განსხვავება ზუსტად იგივეა, რაც attractor-ის მიერ mover-ის მიზიდვასა და mover-ის მიერ attractor-ის მიზიდვას შორის. მე-4 ვარიანტი ყველაზე ხელსაყრელი ჩანს, ყოველ შემთხვევაში, ახლა ამ კურსში რა ეტაპზეც ვართ, იმ შემთხვევისთვის. ჩვენ დიდი დრო დავუთმეთ applyForce() მეთოდის გამოყვანას და ვფიქრობ, ჩვენი მაგალითები უფრო ნათელი იქნება, თუ იმავე მეთოდოლოგიით გავაგრძელებთ.
სხვა სიტყვებით, ჩვენ ერთხელ გვქონდა:
var f = new PVector(0{,}1, 0); // გამოგონილი ძალა
mover.applyForce(f);
ახლა გვექნება:
var f = a.calculateAttraction(m); // მიმზიდველი ძალა ორ ობიექტს შორის
mover.applyForce(f);
და, შესაბამისად, ჩვენი draw() ფუნქციის ჩაწერა შესაძლებელია შემდეგნაირად:
draw = function() {
    background(50, 50, 50);

    // მიზიდულობის ძალის გამოთვლა და მისი მოდება
    var f = a.calculateAttraction(m);
    mover.applyForce(f);

    attractor.display();
    mover.update();
    mover.display();
};
თითქმის მოვრჩით. ვინაიდან გადავწყვიტეთ, calculateAttraction() მეთოდი ჩაგვესვა Attractor ობიექტის ტიპის შიგნით, მოგვიწევს ამ ფუნქციის დაწერა. ფუნქციამ უნდა მიიღოს Mover ობიექტი და დააბრუნოს PVector. და რა ხდება ამ ფუნქციაში? მთელი ის მათემატიკა, რომელიც გრავიტაციული მიზიდვისთვის გამოვიყვანეთ!
Attractor.prototype.calculateAttraction = function(mover) {

    // რა არის ძალის მიმართულება?
    var force = PVector.sub(this.position, mover.position);    
    var distance = force.mag();
    force.normalize();

    // რა არის ძალის მნიშვნელობა?
    var strength = (this.G * this.mass * mover.mass) / (distance * distance);
    force.mult(strength);

    // დავაბრუნოთ ძალა, რათა მისი გამოყენება შევძლოთ!
    return force;
};
და მოვრჩით. დაახლოებით. თითქმის. ერთ პატარა რაღაცაზე მუშაობა გვჭირდება. კიდევ ერთხელ შევხედოთ ზედა კოდს. ხედავთ გაყოფის სიმბოლოს? როდესაც ეს სიმბოლო გვაქვს, უნდა ვკითხოთ საკუთარ თავს: რა მოხდება, თუ მანძილი იქნება ძალიან ძალიან მცირე რიცხვი ან უარესი — 0??! ვიცით, რომ ნულზე გაყოფა არ შეგვიძლია, და თუ რიცხვს გავყოფთ ისეთ მცირე რიცხვზე, როგორიცაა, მაგალითად, 0,0001, ეს იგივეა, რაც ამ რიცხვის გამრავლება 10 000-ზე! დიახ, ეს არის რეალური სამყაროს ფორმულა გრავიტაციის ძალის სიდიდისთვის, მაგრამ ჩვენ რეალურ სამყაროში არ ვცხოვრობთ. ჩვენ ვცხოვრობთ ProcessingJS-ის სამყაროში. და ProcessingJS-ის სამყაროში შეიძლება, მოძრავი (mover-ი) ძალიან ძალიან ახლოს იყოს მიმზიდველთან და ძალა შეიძლება, გახდეს იმდენად ძლიერი, რომ მოძრავი ეკრანიდან გაფრინდეს. ამიტომ, კარგი იქნება, თუ პრაქტიკულად მივუდგებით ამ ფორმულას და დისტანციის დიაპაზონს შევზღუდავთ. შეიძლება, არა აქვს მნიშვნელობა, რეალურად სად არის Mover-ი, მაინც არასოდეს უნდა მიუახლოვდეს ის მიმზიდველს 5 პიქსელზე უფრო ახლოს და არ უნდა დაშორდეს მას 25 პიქსელზე მეტით.
distance = constrain(distance, 5, 25);
იმავე მიზეზით, რის გამოც შევზღუდეთ მინიმალური მანძილი, უნდა შევზღუდოთ მაქსიმალურიც. მაგალითად, თუ მოძრავი არის 500 პიქსელით შორს მიმზიდველისგან (უაზრობაა), ძალას გავყოფდით 250 000-ზე. ეს ძალა შეიძლება, იმდენად სუსტი იყოს, რომ ვერც კი შევამჩნიოთ, რომ მას ვიყენებთ.
ახლა თქვენზეა დამოკიდებული, როგორი ქცევები გსურთ. მაგრამ თუ გსურთ რეალობასთან მიახლოებული მიზიდვა, რომელიც არასდროს არის აბსურდულად სუსტი ან ძლიერი, მაშინ მანძილის შეზღუდვა კარგი ტექნიკაა.
ახლა ეს ყოველივე ერთად ჩავსვათ პროგრამაში. Mover ობიექტის ტიპი საერთოდ არ შეცვლილა, მაგრამ ახლა ჩვენი პროგრამა მოიცავს Attractor ობიექტს და კოდს, რომელიც მათ ერთმანეთთან აკავშირებს. პროგრამაში აგრეთვე დავამატეთ კოდი მიმზიდველის მაუსით გასაკონტროლებლად, რათა შედეგებზე დაკვირვება გაგვეადვილებინა.
ცხადია, შეგვეძლო, გაგვეფართოვებინა ეს მაგალითი მასივის გამოყენებით ბევრი Mover ობიექტის შემოსატანად, როგორც ხახუნისა და ბლანტი ხახუნის შემთხვევაში ვქენით. ძირითადი ცვლილება, რაც პროგრამაში გავაკეთეთ, არის ჩვენი Mover ობიექტის შეცვლა ისე, რომ მიიღოს მასა, x, და y (როგორც ადრე გაგვიკეთებია), შემთხვევით ადგილებზე დალაგებული Mover-ების მასივის ინიციალიზაცია და ამ მასივზე გადაყოლა თითოეულ მათგანზე მიზიდულობის ძალის გამოსათვლელად ყოველ ჯერზე:
var movers = [];
var attractor = new Attractor();

for (var i = 0; i < 10; i++) {
    movers[i] = new Mover(random(0{,}1, 2), random(width), random(height));
}

draw = function() {
    background(50, 50, 50);

    attractor.display();
    for (var i = 0; i < movers.length; i++) {
        var force = attractor.calculateAttraction(movers[i]);
        movers[i].applyForce(force);

        movers[i].update();
        movers[i].display();
    }
};
ეს „ბუნებრივი სიმულაციების" კურსი ეფუძნება დანიელ შიფმენის წიგნს "კოდის ბუნებას", ის გამოყენებულია ლიცენზიით Creative Commons Attribution-NonCommercial 3,0 Unported License.

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

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