ძირითადი მასალა
კომპიუტერული პროგრამირება
კურსი: კომპიუტერული პროგრამირება > თემა 4
გაკვეთილი 5: მეხსიერების თამაშის აგებამეხსიერების თამაში: ფილების ამოტრიალება
კარგი, ახლა გვაქვს ფილების ბადე, რომლის ჩვენებაც შეგვიძლია წაღმა ან უკუღმა. მაგრამ ვერანაირად ვერ ვითამაშებთ თამაშს. შეგახსენებთ, აი, ასეთია თამაში:
- როდესაც თამაში დაიწყება, ყველა ფილა არის უკუღმაn.
- შემდეგ მოთამაში ატრიალებს ორ კარტს, მათ ნიშნავს მათზე დაწკაპუნებით.
- თუ ორ ფილას აქვს ერთი და იგივე სურათი, ისინი რჩებიან წაღმა. წინააღმდეგ შემთხვევაში, მცირეოდენი დაყოვნების შემდეგ ისინი ისევ უნდა გადაბრუნდნენ უკუღმა.
დაწკაპუნებისას ამობრუნებადი ფილები
ახლა ჩვენ გვაქვს პროგრამა, რომელიც ხატავს ფილების ბადეს და შემდეგ სხვას არაფერს ხატავს. გვინდა, რომ ჩვენმა პროგრამამ სხვადასხვა რაიმე დახატოს დროთა განმავლობაში - ის დაიწყებს უკუღმა დადებული ფილების დახატვას, მაგრამ შემდეგ ის გამოაჩენს დაწკაპუნებულ ფილებს და, თუ ყველაფერი კარგად წავა მოთამაშისათვის (თითები გადავაჯვარედინოთ!), ის გამოიტანს გამარჯვების ტექსტს.
ასე რომ, მოდით, დახატვის მთელი კოდი გადავიტანოთ ProcessingJS-ის
draw
ფუნქციაში. კომპიუტერი გააგრძელებს draw()
-ს გამოძახებას, სანამ პროგრამა გაშვებული იქნება, ასე რომ, ფილების დახატვა გაგრძელდება იმის მიხედვით, ისინი წაღმა არიან ამობრუნებული თუ უკუღმა:draw = function() {
background(255, 255, 255);
for (var i = 0; i < tiles.length; i++) {
tiles[i].draw();
}
};
ახლა რამდენიმე ფილა წაღმა ამოვატრიალოთ! ფილის ამოსატრიალებლად მოთამაშემ მას უნდა დააწკაპუნოს. დაწკაპუნებაზე რეაგირებისათვის ProcessingJS-ის პროგრამებში შეგვიძლია, განვსაზღვროთ
mouseClicked
ფუნქცია და კომპიუტერი გაუშვებს ამ კოდს მაუსზე ყოველი დაწკაპუნებისას.mouseClicked = function() {
// დაწკაპების რაიმე გზით დამუშავება
};
როდესაც ჩვენი პროგრამა ხედავს, რომ მოთამაშემ სადღაც დააწკაპუნა, გვინდა,
mouseX
-ისა და mouseY
-ის გამოყენებით შევამოწმოთ, ფილაზე ხომ არ დააწკაპუნა. დავიწყოთ isUnderMouse
მეთოდის დამატებით Tile
-ისთვის, რომელიც აბრუნებს true
-ს (ჭეშმარიტს), თუ მოცემული x და y არის ფილის ტერიტორიაზე.იმ გზის მიხედვით, რითაც ფილები დავხატეთ, ფილის x და y შეესაბამება ფილის ზედა მარცხენა კუთხეს, ასე რომ, ჩვენ უნდა დავაბრუნოთ true მხოლოდ მაშინ, როცა მოცემული x არის
this.x
-სა და this.x + this.width
-ს შორის და მოცემული y არის this.y
-სა და this.y + this.width
-ს შორის:Tile.prototype.isUnderMouse = function(x, y) {
return x >= this.x && x <= this.x + this.width &&
y >= this.y && y <= this.y + this.width;
};
ახლა, როცა ეს მეთოდი გვაქვს, შეგვიძლია, გამოვიყენოთ
for
ციკლი mouseClicked
-ში, რათა შევამოწმოთ, არის თუ არა თითოეული ფილა mouseX
-ისა და mouseY
-ის ქვეშ. თუ ასეა, მაშინ ფილის isFaceUp
თვისებას ვანიჭებთ true
-ს:mouseClicked = function() {
for (var i = 0; i < tiles.length; i++) {
if (tiles[i].isUnderMouse(mouseX, mouseY)) {
tiles[i].isFaceUp = true;
}
}
};
აი, როგორ გამოიყურება ის. დააჭირეთ რამდენიმე ფილას, და ნახეთ, რა მოხდება:
ფილების ამოტრიალებების შეზღუდვა
შეამჩნიეთ რაღაც? ჩვენ განვახორციელეთ თამაშის მხოლოდ ერთი ასპექტის იმპლემენტაცია — მოთამაშეს მივეცით საშუალება, ამოატრიალოს ფილები, მაგრამ გვაკლია ერთი მნიშვნელოვანი შეზღუდვა: მან ვერ უნდა შეძლოს ორზე მეტი ფილის ამოტრიალება ერთ ჯერზე.
თვალყური უნდა ვადევნოთ ამოტრიალებული ფილების რაოდენობას. ამის გაკეთების ერთ-ერთი მარტივი გზა არის გლობალური
numFlipped
ცვლადი, რომელსაც ვზრდით ყოველ ჯერზე, როცა მოთამაშე კარტს ატრიალებს. ჩვენ მხოლოდ იმ შემთხვევაში ვატრიალებთ ფილას, თუ numFlipped
არის 2-ზე ნაკლები და ფილა უკვე არ დევს წაღმა:var numFlipped = 0;
mouseClicked = function() {
for (var i = 0; i < tiles.length; i++) {
var tile = tiles[i];
if (tiles.isUnderMouse(mouseX, mouseY)) {
if (numFlipped < 2 && !tile.isFaceUp) {
tile.isFaceUp = true;
numFlipped++;
}
}
}
};
ფილების ამოტრიალების დაყოვნება
კარგი, ორი ფილის ამოტრიალების ჩვენი ლოგიკა დასრულებულია. შემდეგ რა ვქნათ? კიდევ ერთხელ შევაჯამოთ თამაშის წესები:
თუ ორივე ფილას აქვს ერთი და იგივე სურათი, ისინი წაღმა რჩებიან. წინააღმდეგ შემთხვევაში, ფილები მცირე დროის შემდეგ ისევ უკუღმა გადატრიალდებიან.
ჯერ განვახორციელებთ მეორე ნაწილის იმპლემენტაციას, რაც ავტომატურად გადაატრიალებს ფილებს უკუღმა, რადგან რთული იქნება პირველი ნაწილის დატესტვა, თუ ახალი დამთხვევების ადვილად მოძებნა არ შეგვიძლია.
ჩვენ ვიცით, როგორ უნდა გადავატრიალოთ ფილები უკუღმა
isFaceUp
-ის false
მნიშვნელობაზე დაყენებით, მაგრამ როგორ ვქნათ ეს დროის გარკვეული პერიოდის შემდეგ? ყველა ენასა და გარემოს აქვს სხვადასხვანაირი მიდგომა კოდის განხორციელების დაყოვნებისადმი და უნდა გავარკვიოთ, როგორ გავაკეთოთ ეს ProcessingJS-ში. გვჭირდება გზა, რომლითაც თვალყურს ვადევნებთ დროს — გავიდა თუ არა დაყოვნების დრო — და კოდის გამოძახების გზა ამ დროის გასვლის შემდეგ. აი, რას შემოგთავაზებდით:- ვქმნით გლობალურ ცვლადს სახელად
delayStartFC
, თავდაპირველად null-ს. mouseClicked
ფუნქციაში, სწორედ მას შემდეგ, რაც მეორე ფილას გადმოვატრიალებთ, ვინახავთframeCount
-ის მიმდინარე მნიშვნელობასdelayStartFC
-ში. ეს ცვლადი გვეუბნება, რამდენმა კადრმა გაიარა მას შემდეგ, რაც პროგრამა გაეშვა, და ეს არის დროის ამოცნობის ერთ-ერთი გზა ჩვენს პროგრამებში.draw
ფუნქციაში ვამოწმებთ,frameCount
ახალი მნიშვნელობა შესამჩნევად უფრო დიდია თუ არა ძველზე, და თუ ასეა, ყველა ფილას ვატრიალებთ დაnumFlipped
-ს ვუტოლებთ 0. ჩვენ აგრეთვე ხელახლა ვაყენებთdelayStartFC
-სnull
-ზე.
ეს მშვენიერი ამოხსნაა, რომლის იმპლემენტაციასაც ბევრი კოდი არ სჭირდება. მუშაობის ეფექტურობის გასაუმჯობესებლად შეგვიძლია, გამოვიყენოთ
loop
და noLoop
ფუნქციები, რათა draw
-ს (დახატვის) კოდი მხოლოდ მაშინ იქნას გამოძახებული, როცა შეყოვნება ხდება. აი, ყველაფერი ერთად:var numFlipped = 0;
var delayStartFC = null;
mouseClicked = function() {
for (var i = 0; i < tiles.length; i++) {
var tile = tiles[i];
if (tile.isUnderMouse(mouseX, mouseY)) {
if (numFlipped < 2 && !tile.isFaceUp) {
tile.isFaceUp = true;
numFlipped++;
if (numFlipped === 2) {
delayStartFC = frameCount;
}
loop();
}
}
}
};
draw = function() {
if (delayStartFC &&
(frameCount - delayStartFC) > 30) {
for (var i = 0; i < tiles.length; i++) {
tiles[i].isFaceUp = false;
}
numFlipped = 0;
delayStartFC = null;
noLoop();
}
background(255, 255, 255);
for (var i = 0; i < tiles.length; i++) {
tiles[i].draw();
}
};
გადაატრიალეთ რამდენიმე ფილა ქვემოთ - მაგარია, როგორ ტრიალდებიან ფილები ავტომატურად, არა? ამის უფრო ღრმად გასაგებად სცადეთ დაყოვნების დროის და დაყოვნების დასაწყებად საჭირო რაოდენობის ფილების შეცვლა.
დამთხვევების შემოწმება
თუ ნებისმიერი ფილების დამთხვევა შეძელით ზემოთ, ალბათ, გეწყინათ, რომ ისინი მაინც გადატრიალდნენ, რადგან, ჰეი, თქვენ დამთხვევა იპოვეთ! ასე რომ, ახლა თამაშის ამ წესის იმპლემენტაციის დროა:
თუ ორი ფილა ერთმანეთს ემთხვევა, მაშინ ისინი წაღმა უნდა დარჩნენ.
ეს ნიშნავს, რომ ჩვენ უნდა შევამოწმოთ ფილების დამთხვევა ყოველთვის, როცა 2 ფილა არის ამოტრიალებული, და მანამ, სანამ დაყოვნებას დავიწყებთ. ფსევდო-კოდის სახით ეს ასეთი იქნება:
თუ ორი ფილა არის ამოტრიალებული:
თუ პირველ ფილას აქვს ისეთივე სურათი, როგორიც მეორეს:
დავტოვოთ ფილები წაღმა
ჩვენ უკვე ვამოწმებთ, არის თუ არა ორი ფილა ამოტრიალებული (
numFlipped === 2
), ასე რომ, როგორ შევამოწმოთ, აქვთ თუ არა ფილებს ერთი და იგივე სურათი? პირველ ყოვლისა, გვჭირდება რაიმე გზა, რომლითაც გვექნება წვდომა ორ ამოტრიალებულ ფილაზე. როგორ ვიპოვოთ ისინი?შეგვეძლო, ყოველ ჯერზე გადავყოლოდით ჩვენს მასივს, გვეპოვა ყველა ფილა, რომელსაც
isFaceUp
ცვლადი უყენია true-ზე, და შემდეგ შეგვენახა ისინი მასივში.აი, ამის გაკეთების უფრო მოკლე გზა: მოდით, ყოველთვის შევინახოთ ჩვენი ამოტრიალებული ფილები მასივში მარტივი წვდომისათვის. ასე გაკეთების შემთხვევაში არ გვჭირდება მთელ
tiles
მასივზე გადაყოლა ყოველ ჯერზე, როცა მოთამაშე ატრიალებს ფილას.დასაწყისისთვის შეგვიძლია,
numFlipped
შევცვალოთ მასივით და შემდეგ გამოვიყენოთ flippedTiles.length
ყველგან, სადაც იქამდე ვიყანებდეთ numFlipped
-ს. ჩვენი mouseClick
ფუნქცია გამოიყურება ასე:var flippedTiles = [];
var delayStartFC = null;
mouseClicked = function() {
for (var i = 0; i < tiles.length; i++) {
var tile = tiles[i];
if (tile.isUnderMouse(mouseX, mouseY)) {
if (flippedTiles.length < 2 && !tile.isFaceUp) {
tile.isFaceUp = true;
flippedTiles.push(tile);
if (flippedTiles.length === 2) {
delayStartFC = frameCount;
loop();
}
}
}
}
};
ახლა უნდა გავარკვიოთ, აქვს თუ არა
flippedTiles
მასივში მოცემულ ორ ფილას იგივე სურათი (ინგლ. face). რა არის face
თვისება? ეს არის ობიექტი — ხოლო თუ ფილები ერთმანეთს ემთხვევა, მაშინ მათი სურათები ზუსტად ერთი და იგივე ობიექტი უნდა იყოს, ისევე, როგორც ცვლადის შემთხვევაში, როცა ცვლადი კომპიუტერის მეხსიერებაში ორივესთვის ერთსა და იმავე ადგილზე მიუთითებს. ეს იმიტომ, რომ ჩვენ შევქმენით თითოეული სურათის ობიექტი ერთხელ (როგორც getImage("avatars/old-spice-man")
-ის შემთხვევაში) და შემდეგ ერთისა და იმავე სურათის ობიექტი ორჯერ დავამატეთ სურათების მასივს:var face = possibleFaces[randomInd];
selected.push(face);
selected.push(face);
JavaScript-ში მაინც, ტოლობის ოპერატორი დააბრუნებს true-ს, თუ ის გამოყენებულია ორ ცვლადზე, რომლებიც მიუთითებენ ობიექტებზე, და ეს ორივე ცვლადი მიუთითებს ერთსა და იმავე ობიექტზე მეხსიერებაში. ეს ნიშნავს, რომ ჩვენი შემოწმება შეიძლება, მარტივი იყოს — უბრალოდ, გამოვიყენოთ ტოლობის ოპერატორი თითოეული ფილის
face
თვისებაზე:if (flippedTiles[0].face === flippedTiles[1].face) {
...
}
ახლა, როცა ვიცით, რომ ფილები ემთხვევა, ისინი წაღმა უნდა დავტოვოთ. ჯერჯერობით, ისინი ისევ გადაბრუნდებოდნენ დაყოვნების შემდეგ. ამ შემთხვევაში შეგვეძლო, არ შეგვექმნა ანიმაცია, მაგრამ გახსოვდეთ, რომ მოგვიანებით იქნება ანიმაცია - ასე რომ, ამის იმედად ვერ ვიქნებით.
ამის ნაცვლად, გვჭირდება გზა, რომლითაც გავიგებთ შემდეგს: „ჰეი, როდესაც ყველას ისევ გადავაბრუნებთ, კონკრეტულად ესენი არ უნდა გადავაბრუნოთ“. როგორც ჩანს, ბულის ცვლადიანი თვისების გამოყენებისთვის მშვენიერი დროა!
Tile
-ის კონსტრუქტორს დავამატოთ isMatch
თვისება და შემდეგ isMatch
დავაყენოთ true
-ზე იმ if
პირობაში:if (flippedTiles[0].face === flippedTiles[1].face) {
flippedTiles[0].isMatch = true;
flippedTiles[1].isMatch = true;
}
ახლა ამ თვისების გამოყენება შეგვიძლია იმისთვის, რომ გადავწყვიტოთ, გადავაბრუნოთ თუ არა ფილა.
for (var i = 0; i < tiles.length; i++) {
var tile = tiles[i];
if (!tile.isMatch) {
tile.isFaceUp = false;
}
}
ითამაშეთ ქვემოთ! როდესაც იპოვით ორ ფაილს, რომლებიც ერთმანეთს ემთხვევა, ისინი დაყოვნების (და მომავალი სვლების) შემდეგ წაღმა უნდა დარჩნენ:
გსურთ, შეუერთდეთ დისკუსიას?
პოსტები ჯერ არ არის.