8.1 Başlangıç
İlk örnek çalışmamızda GASP paketi yardımıyla basit bir oyun geliştireceğiz. Oyunda bir top pencerenin solundan sağına hareket edecek ve siz bu topu yakalamak için sağ taraftaki bir eldiven
i hareket ettireceksiniz.
8.2 Topu hareket ettirmek için while
kullanımı
while
cümeleleri gasp
ile birlikte programa hareket katmak için kullanılabilir. Aşağıdaki program siyah bir topu 800 x 600 piksel boyutlarında bir grafik tuvalinde hareket ettirmektedir. Bu programı pitch.py
isminde bir dosyaya koyun:
from gasp import * begin_graphics(800, 600, title="Catch", background=color.YELLOW) set_speed(120) ball_x = 10 ball_y = 300 ball = Circle((ball_x, ball_y), 10, filled=True) dx = 4 dy = 1 while ball_x < 810: ball_x += dx ball_y += dy move_to(ball, (ball_x, ball_y)) update_when('next_tick') end_graphics()
Top ekran boyunca hareket ettikçe, aşağıdaki gibi bir grafik penceresi göreceksiniz:
Programdaki ilk bir kaç döngüyü inceleyerek x
ve y
değişkenlerine ne olduğunu anlamaya çalışın.
Bu örnekten GASP hakkında öğrenilecek yeni şeyler:
begin_graphics
fonksiyonu grafik tuvali için genişlik, yükseklik, başlık ve arka plan rengi argümanlarını alıyor.set_speed
kare (çerçeve) sayısını (Frame Rate) saniyedeki kare sayısı (fps - Frame Per Second) olarak alıyor.Circle(...)
fonksiyonunafilled=True
eklediğimizde ortaya çıkan çemberin dolu olması sağlanıyor.ball = Circle
çemberin (çemberin gerçekte ne olduğunu daha sonra konuşacağız)ball
isimli bir değişkende saklanmasını sağlıyor, böylece daha sonra da erişilebiliyor.- GASP'taki
move_to
fonksiyonu programcının bir şekli (bu örnekte top şekli) verilen konum parametresine göre konumlandırmasını sağlıyor. update_when
fonksiyonu GASP'ın belli bir olay olana kadar eylemi geciktirmesini sağlıyor.'next_tick'
olayı bir sonraki çerçeveye kadar bekler, bu daset_speed
ile belirlenmiş olan çerçeve sayısıdır.update_when
için diğer geçerli argümanlar'key_pressed'
(tuşa basıldı) ve'mouse_clicked'
(fare tıklandı) argümanlarıdır.
8.3 Aralıkları değiştirmek
Oyunumuzu daha ilginç kılmak için, topumuzun hız ve doğrultusunu değiştirmek isteyebiliriz. GASP random_between(alt, ust)
isminde ve alt
ve ust
aralığında rastgele tamsayı değer üreten bir fonksiyona sahiptir. Bunun nasıl çalıştığını görmek için, aşağıdaki programı çalıştırın:
from gasp import * i = 0 while i < 10: print random_between(-5, 5) i += 1
Fonksiyon her çağrıldığında -5 ve 5 aralığında küçük veya büyük bir rastgele tamsayı değer seçilmektedir. Bu programı çalıştırdığımızda aşağıdaki sonuçları görüyoruz:
-2 -1 -4 1 -2 3 -5 -3 4 -5
Siz muhtemelen daha farklı sayılar göreceksiniz.
random_between
fonksiyonunu topun yönünü değiştirmek için kullanalım. pitch.py
programında y
değişkenine 1
atayan kısmı değiştirelim:
dy = 1
yukarıdaki kısım yerine -4 ve 4 arasında rastgele bir değer üreten aşağıdaki satırı yazalım:
dy = random_between(-4, 4)
8.4 Topun sekmesini
sağlamak
Bu programın yeni halini çalıştırdığınızda, topun arada sırada ekranın üst veya alt sınırını aştığını göreceksiniz. Bunu önlemek için topun kenarlardan sekmesini
, dy
'nin işaretini değiştirip topu zıt dikey yöne gönderelim
Aşağıdaki kodu pitch.py
programında while döngüsünün gövdesinde ilk satıra ekleyin:
if ball_y >= 590 or ball_y <= 10: dy *= -1
Nasıl davrandığını iyice anlamak için programı bir kaç kez çalıştırın.
8.5 break
cümlesi
break cümlesi bir döngünün gövdesini hemen terketmek için kullanılır. Aşağıdaki program basit bir tahmin oyununu gerçekleştirmektedir:
from gasp import * number = random_between(1, 1000) guesses = 1 guess = input("Guess the number between 1 and 1000: ") while guess != number: if guess > number: print "Too high!" else: print "Too low!" guess = input("Guess the number between 1 and 1000: ") guesses += 1 print "\n\nCongratulations, you got it in %d guesses!\n\n" % guesses
break
cümlesi yazarak bu programda input
cümlesinin tekrar tekrar kullanımının önüne geçebiliriz:
from gasp import * number = random_between(1, 1000) guesses = 0 while True: guess = input("Guess the number between 1 and 1000: ") guesses += 1 if guess > number: print "Too high!" elif guess < number: print "Too low!" else: print "\n\nCongratulations, you got it in %d guesses!\n\n" % guesses break
Bu program matematiksel bir yasa olan üçe bölünme (trichotomy)yi (verilen gerçel sayılar a ve b için a > b, a < b, veya a = b) kullanır. Her iki sürümde her ne kadar 15 satır olsa da, ikinci sürümdeki mantığın daha anlaşılır olduğunu söyleyebiliriz.
Bu programı guess.py
isminde bir dosyaya koyun.
8.6 Klavyeyi yanıtlamak
Aşağıdaki program bir çember (veya eldiven
) yaratmaktadır, bu çember klavye girdisine göre tepki vermektedir. j
veya k
tuşlarına basmak eldiveni sırasıyla yukarı ve aşağı hareket ettirmektedir. Bu programı mitt.py
isminde bir dosyaya yazın:
from gasp import * begin_graphics(800, 600, title="Catch", background=color.YELLOW) set_speed(120) mitt_x = 780 mitt_y = 300 mitt = Circle((mitt_x, mitt_y), 20) while True: if key_pressed('k') and mitt_y <= 580: mitt_y += 5 elif key_pressed('j') and mitt_y >= 20: mitt_y -= 5 if key_pressed('escape'): break move_to(mitt, (mitt_x, mitt_y)) update_when('next_tick') end_graphics()
mitt.py
'yi çalıştırın, j
ve k
tuşlarına basarak eldiveni ekranda yukarı aşağı hareket ettirin.
8.7 Çarpışma kontrolü
Aşağıdaki program iki topu birbirine doğru ekranın karşıt yönlerinden hareket ettirir. Çarpıştıklarında
, her iki top kaybolur ve program sonlanır:
from gasp import * def distance(x1, y1, x2, y2): return ((x2 - x1)**2 + (y2 - y1)**2)**0.5 begin_graphics(800, 600, title="Catch", background=color.YELLOW) set_speed(120) ball1_x = 10 ball1_y = 300 ball1 = Circle((ball1_x, ball1_y), 10, filled=True) ball1_dx = 4 ball2_x = 790 ball2_y = 300 ball2 = Circle((ball2_x, ball2_y), 10) ball2_dx = -4 while ball1_x < 810: ball1_x += ball1_dx ball2_x += ball2_dx move_to(ball1, (ball1_x, ball1_y)) move_to(ball2, (ball2_x, ball2_y)) if distance(ball1_x, ball1_y, ball2_x, ball2_y) <= 20: remove_from_screen(ball1) remove_from_screen(ball2) break update_when('next_tick') sleep(1) end_graphics()
Bu programı collide.py
isminde bir dosyaya koyup, çalıştırın.
8.8 Parçaları birleştirelim
Hareket eden topu, eldiveni, ve çarpışma kontrolünü birleştirmek için tek bir while
döngüsüne ihtiyaç duyuyoruz. Bu döngüde her bir olay sırasıyla gerçekleşir:
from gasp import * def distance(x1, y1, x2, y2): return ((x2 - x1)**2 + (y2 - y1)**2)**0.5 begin_graphics(800, 600, title="Catch", background=color.YELLOW) set_speed(120) ball_x = 10 ball_y = 300 ball = Circle((ball_x, ball_y), 10, filled=True) dx = 4 dy = random_between(-4, 4) mitt_x = 780 mitt_y = 300 mitt = Circle((mitt_x, mitt_y), 20) while True: # move the ball if ball_y >= 590 or ball_y <= 10: dy *= -1 ball_x += dx if ball_x > 810: # the ball has gone off the screen break ball_y += dy move_to(ball, (ball_x, ball_y)) # check on the mitt if key_pressed('k') and mitt_y <= 580: mitt_y += 5 elif key_pressed('j') and mitt_y >= 20: mitt_y -= 5 if key_pressed('escape'): break move_to(mitt, (mitt_x, mitt_y)) if distance(ball_x, ball_y, mitt_x, mitt_y) <= 30: # ball is caught remove_from_screen(ball) break update_when('next_tick') end_graphics()
Bu programı catch.py
isminde bir dosyaya koyup, bir kaç kez çalıştırın. Bazı durumlarda topu yakalamayı
, diğer bazı durumlarda da kaçırmayı deneyin.
8.9 Metin gösterimi
Bu program her kullanıcı hem de bilgisayar için ekran üzerinde skoru gösterir. 0 veya 1 olan rastgele bir sayı üretir (yazı tura gibi) ve eğer değer 1 ise kullanıcıya 1 puan ekler, aksi durumda bilgisayara bir puan ekler. Daha sonra ekrandaki metini günceller.
from gasp import * begin_graphics(800, 600, title="Catch", background=color.YELLOW) set_speed(120) player_score = 0 comp_score = 0 player = Text("Player: %d Points" % player_score, (10, 570), size=24) computer = Text("Computer: %d Points" % comp_score, (640, 570), size=24) while player_score < 5 and comp_score < 5: sleep(1) winner = random_between(0, 1) if winner: player_score += 1 remove_from_screen(player) player = Text("Player: %d Points" % player_score, (10, 570), size=24) else: comp_score += 1 remove_from_screen(computer) computer = Text("Computer: %d Points" % comp_score, (640, 570), size=24) if player_score == 5: Text("Player Wins!", (340, 290), size=32) else: Text("Computer Wins!", (340, 290), size=32) sleep(4) end_graphics()
Bu programı scores.py
isminde bir dosyaya yazıp, çalıştırın.
catch.py
programını kazananı gösterecek şekilde güncelleyebiliriz. if ball_x > 810:
koşulundan hemen sonra, aşağıdakileri ekleyin:
Text("Bilgisayar kazandı!", (340, 290), size=32) sleep(2)
Oyuncunun kazandığını gösterme işi size bir alıştırma olarak bırakılmıştır.
8.10 Soyutlama
Programımız biraz karmaşıklaşmaya başladı. Durumu daha da kötü kılmaz için, karmaşasını daha da arttıracağız. Bir sonraki geliştirme aşaması içiçe döngü gerektiriyor. Dış döngü bilgisayar veya kullanıcı kazanma sayısına ulaşana kadar turları tekrarlayacak. İç döngü ise halihazırda sahip olduğumuz döngü olacak, bu döngü tek bir tur oynanmasını sağlıyor, topu ve eldiveni hareket ettiriyor ve yakalama veya kaçırma gerçekleşti mi diye kontrol ediyor.
Araştırmacılar bilişsel görevlerimizi işleme yeteneğimizin açık sınırları olduğunu gösteriyor (George A. Miller tarafından yazılmış olan The Magical Number Seven, Plus or Minus Two: Some Limits on our Capacity for Processing Information incelenebilir). Program karmaşıklaştıkça, deneyimli bir programcının bile onu geliştirmesi, anlaması ve bakımını yapması zorlaşıyor.
Artan karmaşıklığı karşılayabilmek için, ilişkili cümleleri fonksiyonlar şeklinde ayrıştırmak, program ayrıntılarını gizleyerek soyutlama yapmak gerekir. Bu aynı kavramdaki, kapsamdaki programlama cümlelerine bir grup şeklinde davranmamızı sağlar, zihinsel veri yolumuzu boşaltarak sonraki görevlere bizi hazırlar. Soyutlamayı kullanma yeteneği bilgisayar programlamadaki en güçlü fikirlerden biridir.
Aşağıdaki catch.py
programının bitmiş halini inceleyebilirsiniz:
from gasp import * COMPUTER_WINS = 1 PLAYER_WINS = 0 QUIT = -1 def distance(x1, y1, x2, y2): return ((x2 - x1)**2 + (y2 - y1)**2)**0.5 def play_round(): ball_x = 10 ball_y = random_between(20, 280) ball = Circle((ball_x, ball_y), 10, filled=True) dx = 4 dy = random_between(-5, 5) mitt_x = 780 mitt_y = random_between(20, 280) mitt = Circle((mitt_x, mitt_y), 20) while True: if ball_y >= 590 or ball_y <= 10: dy *= -1 ball_x += dx ball_y += dy if ball_x >= 810: remove_from_screen(ball) remove_from_screen(mitt) return COMPUTER_WINS move_to(ball, (ball_x, ball_y)) if key_pressed('k') and mitt_y <= 580: mitt_y += 5 elif key_pressed('j') and mitt_y >= 20: mitt_y -= 5 if key_pressed('escape'): return QUIT move_to(mitt, (mitt_x, mitt_y)) if distance(ball_x, ball_y, mitt_x, mitt_y) <= 30: remove_from_screen(ball) remove_from_screen(mitt) return PLAYER_WINS update_when('next_tick') def play_game(): player_score = 0 comp_score = 0 while True: pmsg = Text("Player: %d Points" % player_score, (10, 570), size=24) cmsg = Text("Computer: %d Points" % comp_score, (640, 570), size=24) sleep(3) remove_from_screen(pmsg) remove_from_screen(cmsg) result = play_round() if result == PLAYER_WINS: player_score += 1 elif result == COMPUTER_WINS: comp_score += 1 else: return QUIT if player_score == 5: return PLAYER_WINS elif comp_score == 5: return COMPUTER_WINS begin_graphics(800, 600, title="Catch", background=color.YELLOW) set_speed(120) result = play_game() if result == PLAYER_WINS: Text("Player Wins!", (340, 290), size=32) elif result == COMPUTER_WINS: Text("Computer Wins!", (340, 290), size=32) sleep(4) end_graphics()
Bu örnekten öğrenilecek yeni şeyler:
- İyi düzenleme (örgütleme) pratiklerini izlemek programların okunurluğunu arttıracaktır. Programlarınızda aşağıdaki düzenleme yaklaşımını kullanın:
- import cümleleri
- genel (global) sabitler
- fonksiyon tanımlamaları
- programın ana gövdesi
COMPUTER_WINS
,PLAYER_WINS
, veQUIT
gibi sembolik sabitler programın okunurluğunu arttırmak için kullanılabilir. İsim sabitlerinin tüm harflerini büyük yazmak gelenekselleşmiş bir yaklaşımdır. Python'dasabit
e yeni değer atamak (ve atamamak) tamamen programcının kontrolündedir, dil bunu kısıtlamak için bir kolay yol sunmamaktadır (çoğu diğer programlama dilleri bu kolay yolu sunar).- 8.8 nolu bölümde geliştirilen programı aldık ve
play_round()
isminde bir fonksiyon içerisine yerleştirdik.play_round
fonksiyonu programın üstünde tanımladığımız sabitleri kullanmaktadır. Kendisine atanan sayısal değeri hatırlamaktansaCOMPUTER_WINS
sabit ismini hatırlamak daha kolaydır. play_game()
ismindeki yeni fonksiyonplayer_score
vecomp_score
için değişkenler yaratır.while
döngüsü kullanarakplay_round
fonksiyonunu tekrar tekrar çağırır. Her bir çağrımda sonucu kontrol edip, skoru uygun şekilde günceller. Son olarak eğer bilgisayar veya kullanıcı 5 puana ulaşırsa,play_game
fonksiyonu programın ana gövdesine kazananı geri döndürür, ana program gövdesi de kazananı görüntüleyip programı sonlandırır.- İki
result
değişkeni vardır --- bir tanesiplay_game
fonksiyonunda, diğeri de programın ana gövdesinde. Her ikisi de aynı isme sahip olsa da, farklı isim uzayındalar, birbirleriyle bir ilişkileri yoktur. Her fonksiyon kendi isim uzayını yaratır ve fonksiyon gövdesinde tanımlı isimler, fonksiyon gövdesinin dışındagörünür
değildir. İsim uzayları sonraki bölümde ayrıntılı olarak anlatılacaktır.
8.11 Sözlük
- rastgele:
- Herhangi bir desene sahip olmayan. Tahmin edilemeyen. Bilgisayarlar tahmin edilebilir olarak tasarlanmıştır, ve bilgisayardan gerçekten rastgele bir değer almak mümkün değildir. Bazı fonksiyonlar rastgeleymiş gibi görünen bazı sayı dizileri üretir, bunlar, Python'da da elde ettiğimiz yalancı rastgele (pseudorandom) değerlerdir.
- üçe bölünme (trichotomy):
- Verilen gerçel sayılar a ve b için, takip eden ilişkilerden sadece bir tanesinin sağlanmasıdır: a < b, a > b, veya a = b. Böylece eğer ilişkilerden ikisinin yanlış olduğunu belirlediğinizde, diğer ilişkinin doğru olduğunu kabul edebilirsiniz.
- iç döngü:
- Bir başka döngü içinde yer alan döngü.
- soyutlama:
- Bir kavramın bilgi içeriğinin azaltılmasıyla sağlanan genelleştirme. Python'daki fonksiyonlar cümleleri gruplamak tek bir isim altında gruplamak için, ayrıntıları soyutlamak ve programın anlaşılırlığını kolaylaştırmak için kullanılabilir.
- sabit:
- Program çalışması sırasında değişmeyen nümerik değer. Sabitleri temsil etmek için tamamen büyük harflerden oluşan isimler kullanmak gelenekselleşmiştir. Python programlarında sabitlerin değişmemesi programcıya bırakılmıştır, Python'da gerçek sabitleri sağlamak üzere herhangi bir dil düzeneği yoktur.
8.12 Alıştırmalar
-
mitt.py
çalışırken <Escape> tuşuna basmanız durumunda ne olur? Programda bu davranışı yaratan iki satırı bulup nasıl çalıştığını anlatın. guess.py
'deki sayaç değişkeninin ismi nedir? Uygun bir strateji ile, doğruya ulaşmak için gereken maksimum tahmin sayısı 11'dir. Bu strateji nedir?mitt.py
programındakieldiven
grafik penceresinin en üst veya en altına gelirse ne olur? Programda bu davranışı kontrol eden satırları bulun ve satırın nasıl çalıştığını ayrıntılı olarak anlatın.collide.py
programındakiball1_dx
değişkeninin değerini 2 olarak değiştirin. Program hangi farklı şekilde davranmaktadır? Şimdiball1_dx
değişkenini tekrar 4 olarak değiştirin, veball2_dx
değerini -2 olarak değiştirin. Ayrıntılı olarak bu değişikliklerin davranışta yarattığı farklılıkları anlatın.collide.py
programındakibreak
cümlesini yorum haline (başına#
koyarak yapabilirsiniz) getirin. Programın davranışında herhangi bir fark görüyor musunuz? Şimdiremove_from_screen(ball1)
cümlesini de yorum haline getirin. Şimdi ne oluyor? Bu iki satırın birlikte gerekli davranışı nasıl ortaya çıkardığını iyice anlamak için yorum haline getirme ve normal hale getirme denemeleri yapın, ayrıntılı olarak bu cümlelerin nasıl çalıştığını anlatın.- Aşağıdaki satırları 8.8 bölümündeki
catch.py
programında nereye eklemelisiniz ki topyakalandığında
programda mesaj görüntülensin?Text("Player Wins!", (340, 290), size=32) sleep(2)
catch.py
programının son sürümündeplay_round
fonksiyonunun işlenmesi esnasında <Escape> tuşuna basıldığındaki çalışma akışını izleyin. Bu tuşa bastığınızda ne oluyor? Neden?catch.py
programının son sürümündeki ana gövdeyi yazın. Her bir satırın ne yaptığını ayrıntılı olarak anlatın. Oyunu başlatan fonksiyonu hangi cümle çağırmaktadır?- Top ve eldiveni göstermekle sorumlu fonksiyonu belirtin. Bu fonksiyon tarafından sağlanan diğer işlemler nelerdir?
- Hangi fonksiyon skorun takibini yapmaktadır? Bu ayrıca skoru gösteren fonksiyon mudur? Yanıtınızı kanıtlamak için kodun bu işlemleri gerçekleştiren ilgili kısımlarını anlatın.
8.13 Proje: pong.py
Pong ilk ticari bilgisayar oyunlarından biriydi. Büyük P ile kendisi bir kayıtlı markadır, ama pong
ifadesi herhangi bir masa tenisi benzeri raketli, toplu oyunları tanımlamak için kullanılır.
catch.py
kendi pong sürümümüzü geliştirmek için gereken programlama araçlarını hali hazırda içermektedir. Artırımsal olarak catch.py
programını pong.py
programına değiştirmek bu projenin hedefidir, aşağıdaki alıştırmaları tamamladığınızda bu hedefe ulaşmış olacaksınız:
catch.py
programınıpong1.py
programı olarak kopyalayın ve eldiveniCircle
yerineBox
kullanarak bir rakete çevirin.Box
hakkında ayrıntılı bilgi için GASP ekine bakabilirsiniz. raketin ekranda kalması için gereken ayarlamaları yapın.pong1.py
programınıpong2.py
programı şeklinde kopyalayın.distance
fonksiyonunu boolean bir fonksiyon olanhit(bx, by, r, px, py, h)
ile değiştirin, bu fonksiyon topun dikey konumu (by
) raketin altında veya üstünde kaldığında ve topun yatay konumu (bx
) raketin önünden çapa (r
) eşit veya daha küçük uzaklıkta iseTrue
döndürür.hit
fonksiyonunu topun rakete değmesini sınamak için kullanın, top rakete değdiğinde (hit
sonuç olarakTrue
döndürdüğünde) topu zıt yatay yönde sektirin. Bitmiş fonksiyonunuz aşağıda doctestleri geçmelidir:def hit(bx, by, r, px, py, h): """ >>> hit(760, 100, 10, 780, 100, 100) False >>> hit(770, 100, 10, 780, 100, 100) True >>> hit(770, 200, 10, 780, 100, 100) True >>> hit(770, 210, 10, 780, 100, 100) False """
Son olarak, skoru top sol taraftan çıktığında kullanıcıya bir puan verecek şekilde değiştirin.pong2.py
programınıpong3.py
programı olarak kopyalayın. Ekranın sol tarafına yeni bir raket ekleyin. Bu raket'a'
tıklandığında yukarı,'s'
tıklandığında aşağı hareket etsin. Top için başlangıç noktasını ekranın ortası (400, 300) olarak değiştirin, her turun başında sol veya sağa rastgele hareket edecek şekilde değiştirin.