Arcade Türü Oyun Programlamayı
ve Bilgisayar Bilimleri ÖğreninChapter 8: Animasyona Giriş
8.1 Sıçrayan Dikdördgen
Animasyonla çalışmaya başlamak için, boş bir ekran açan temel pygame programıyla başlamalıyız.
pygame_base_template.py dosyasının kaynağı şurada bulunabilir:
pygame_base_template.py
Siyah arkaplanlı bir ekranın etrafında beyaz bir dikdörtgeni sıçratan bir program oluşturacağız. Kendi renklerinizi seçmekte özgürsünüz, fakat arkaplan rengini dikdördgenin renginden farklı yaptığınıza emin olmak isteyeceksiniz! Sonuç olarak, bir temel şablon alıp ekran arkaplan rengini beyazdan siyaha çevirerek başlayacağız. Bu kod 46. satır civarında olmalı.
screen.fill(black)
Şimdi oynatacak bir nesne alalım. Basit bir dikdördgen yetecektir. Bu kod ekran temizleme kodunun altında ve onu çeviren (flip) kodtan önce olmalıdır.
pygame.draw.rect(screen,white,[50,50,50,50])
Bu kod döngü her döndüğünde tam olarak (50,50) noktasında bir dikdördgen çizecektir. Bu sayı değişene kadar, kare hareket etmeyecektir.
Değişen bir değer elde etmenin yolu bir değişken kullanmaktır. Alttaki kod bunun ilk aşamasını oluşturur:
rect_x = 50 pygame.draw.rect(screen,white,[rect_x,50,50,50])
Dikdördgeni sağa kaydırmak içni, x her frame'de (çerçevede) bir değer artırılır. Bu kod yapmaya oldukça yakın olmasına rağmen bunu tamamen yapamaz:
rect_x = 50 pygame.draw.rect(screen,white,[rect_x,50,50,50]) rect_x += 1
Yukarıdaki kodta bulunan sorun rect_x'in döngünün her seferinde 50 değerine sıfırlanmasıdır. Bu sorunu çözmek için, rect_x'in başlangıç değeri olan 50'yi döngünün dışına ve üstüne yazmak gerekir. Kodun bu versiyonu sağa doğru başarıyla kayacaktır.
# Dikdördgenin başlangıç pozisyonu rect_x = 50 # -------- Ana Program Döngüsü ----------- while done==False: for event in pygame.event.get(): # Kullanıcı bir şey yaptı if event.type == pygame.QUIT: # Kullanıcı kapat'a bastıysa done=True # Döngüden çıkabilmemiz için işaretle # Ekran arkaplanını ayarla screen.fill(black) pygame.draw.rect(screen,white,[rect_x,50,50,50]) rect_x += 1
Kutuyu daha hızlı hareket ettirmek için rect_x'in değeri şu şekilde artırılabilir:
rect_x += 5
x ve y pozisyonlarının ikisinin de artırılması karenin aşağı ve sağa hareket etmesine sebep olur:
# Dikdördgenin başlangıç pozisyonu rect_x = 50 rect_y = 50 # -------- Ana Program Döngüsü ----------- while done==False: for event in pygame.event.get(): if event.type == pygame.QUIT: done=True # Ekran arkaplanını ayarla screen.fill(black) # Dikdördgeni çiz pygame.draw.rect(screen,white,[rect_x,rect_y,50,50]) # Dikdördgenin taşınma miktarı rect_x += 5 rect_y += 5
Kutuların hareketinde yön ve hız bir vektörün içerisinde saklanabilir. Bu, hareket eden nesnenin yönü ve hızı değiştiğinde işimizi kolaylaştırır. Sonraki kod parçası x ve y'de (5, 5)'lik değişme için değişkenleri kullanmayı gösteriyor.
# Dikdördgenin hızı ve yönü rect_change_x = 5 rect_change_y = 5 # -------- Ana Program Döngüsü ----------- while done==False: for event in pygame.event.get(): # Kullanıcı bir şey yaptı if event.type == pygame.QUIT: # Kullanıcı kapat'a bastıysa done=True # Döngüden çıkabilmemiz için işaretle # Arkaplanı ayarla screen.fill(black) # Dikdördgeni çiz pygame.draw.rect(screen,white,[rect_x,rect_y,50,50]) # Dikdördgeni yeni konumuna taşı rect_x += rect_change_x rect_y += rect_change_y
Kod ekranın kenarına çarptığında gitmeye devam edecektir. Hiçbir şey dikdördgenin ekranın kenarından çarptığında sekmesini sağlamaz. Topun sağa hareket etmesi için yönü değiştirme amacıyla, rect_change_y'un top ekranın kenarına gittiğinde 5'ten -5'e değişmesi gereklidir. rect_y'nin değeri ekranın yüksekliğinden büyük olduğunda top alttadır. Alttaki kod yönü kontrol edip tersine çevirebilir:
# Gerektiğinde topu sektirmek if rect_y > 450: rect_change_y = rect_change_y * -1
Why check rect_y against 450? If the screen is 500 pixels high,
then checking against 500 would be a logical first guess. But the rectangle
is drawn starting from the upper left of the rectangle. So the rectangle
would slide completely off-screen before bouncing. Taking into account
that the rectangle is 50 pixels high:
$500-50=450$.
The code below will bounce the rectangle off all four sides of a 700x400 window:
# Bounce the ball if needed if rect_y > 450 or rect_y < 0: rect_change_y = rect_change_y * -1 if rect_x > 650 or rect_x < 0: rect_change_x = rect_change_x * -1
Daha karışık şekilleri oynatmak için birkaç çizim komutu kullanılabilir. Alttaki kod beyaz dikdördgenin içine kırmızı bir dikdöndgen oluşturuyor. Kırmızı dikdördgen beyaz dikdördgenin sol üst köşesinden x ve y yönlerinde kenarlardan 10 piksel uzaklıktadır. Kırmızı dikdördgenin beyaz tarafından 10 pikselle sarılması sonucu o, iki boyutta da 20 piksel daha geniştir.
# Beyazın içine kırmızı bir dikdördgen çiz. pygame.draw.rect(screen,red,[rect_x+10,rect_y+10,30,30])
8.2 Kar Animasyonu
8.2.1 Kod açıklaması
Bu bölümle çalışmaya başlamak için,, boş bir ekran açan temel pygame programıyla başlamalıyız.
pygame_base_template.py dosyasının kaynağı şurada bulunabilir:
pygame_base_template.py
Rastgele sayıları kullanarak yıldızları, karı veya yağmuru oluşturmak mümkündür. Başlamayı denemenin en basit yolu rastgele x,y pozisyonlarında for döngüsünü kullanarak çemberler çizmektir. Ana while döngüsünün içerisinde alttaki kodu deneyin.
for i in range(50): x=random.randrange(0,400) y=random.randrange(0,400) pygame.draw.circle(screen,white,[x,y],2)
Bu programı çalıştırmak bir sorun gösterecektir. Döngü her döndüğünde, biz yeni rastgele konumlarda yıldızlar çiziyoruz. Program yıldızları saniyede 20 kez yeni konumlara çiziyor!
Yıldızları aynı konumda tutmak için, nerede olduklarının bir listesini tutmak gereklidir. Program bunu yapabilmek için bir Python listesi kullanabilir. Bu ana döngü öncesinde yapılmalıdır, aksi takdirde program saniyenin her 1/20'sinde 50 yeni yıldız ekleyecektir.
for i in range(50): x=random.randrange(0,400) y=random.randrange(0,400) star_list.append([x,y])
Yıldızların konumları eklendiğinde, onlara normal bir liste gibi erişilebilir. Alttaki kod ilk konumdan x ve y koordinatlarını yazdıracaktır:
print( star_list[0] )
Bu kod ilk konumun y değerini yazdıracaktır çünkü koordinat bir listedir ve y değeri ikinci konumdadır:
print( star_list[0][1] )
Ana while döngüsünün içerisinde, program yıldız listesinde (star_list) olan her öğeyi çizmek için for döngüsü kullanabilir. len(star_list) fonksiyonunun yıldız listesindeki eleman sayısını verdiğini unutmayın.
# Listedeki her yıldızı işleme al for i in range(len(star_list)): # Yıldızı çiz pygame.draw.circle(screen,white,star_list[i],2)
Program, kar yağışı gibi, dizideki her nesneyi aşağı hareket ettirecekse alttaki satırın üstte oluşturulan for döngüsüne eklenmesi y koordinatının artmasına sebep olur.
# Yıldızı bir piksel aşağı kaydır star_list[i][1]+=1
Bu, karı aşağı hareket ettirir fakat tek bir kere olur ve ekranda yeni hiçbir şey gerçekleşmez. Alttaki kodu eklersek, bigisayar ekranın üst kısmında rastgele bir yerden kar yağdırmaya başlayacaktır:
# Yıldız ekranın altına hareket ettiyse if star_list[i][1] > 400: # Onu ekranın üst kısmında sıfırla y=random.randrange(-50,-10) star_list[i][1]=y # Ona yeni bir x pozisyonu ver x=random.randrange(0,400) star_list[i][0]=x
8.2.2 Tümünün Listesi
""" Animating multiple objects using a list. Sample Python/Pygame Programs Simpson College Computer Science http://programarcadegames.com/ http://simpson.edu/computer-science/ Explanation video: http://youtu.be/Gkhz3FuhGoI """ # Import a library of functions called 'pygame' import pygame import random # Initialize the game engine pygame.init() BLACK = [0, 0, 0] WHITE = [255, 255, 255] # Set the height and width of the screen SIZE = [400, 400] screen = pygame.display.set_mode(SIZE) pygame.display.set_caption("Snow Animation") # Create an empty array snow_list = [] # Loop 50 times and add a snow flake in a random x,y position for i in range(50): x = random.randrange(0, 400) y = random.randrange(0, 400) snow_list.append([x, y]) clock = pygame.time.Clock() # Loop until the user clicks the close button. done = False while not done: for event in pygame.event.get(): # User did something if event.type == pygame.QUIT: # If user clicked close done = True # Flag that we are done so we exit this loop # Set the screen background screen.fill(BLACK) # Process each snow flake in the list for i in range(len(snow_list)): # Draw the snow flake pygame.draw.circle(screen, WHITE, snow_list[i], 2) # Move the snow flake down one pixel snow_list[i][1] += 1 # If the snow flake has moved off the bottom of the screen if snow_list[i][1] > 400: # Reset it just above the top y = random.randrange(-50, -10) snow_list[i][1] = y # Give it a new x position x = random.randrange(0, 400) snow_list[i][0] = x # Go ahead and update the screen with what we've drawn. pygame.display.flip() clock.tick(20) # Be IDLE friendly. If you forget this line, the program will 'hang' # on exit. pygame.quit()
8.3 3D Animasyon
Oyun fizik kurallarını 2 boyutlu ortamdan 3 boyutlu ortama genişletmek gözüktüğü kadar zor değildir. Bu, bu sınıfın kapsamı dışında olduğu halde, bunun nasıl yapıldığını görmeye uğraşmaya değer.
Blender adı verilen ve programcıların 3D oyun oluşturmalarına imkan sağlayan "oyun motoruna" sahip ücretsiz bir 3 boyutlu program mevcuttur. Oyundaki 3 boyutlu nesneler onların oyundaki hareketlerini kontrol etmek için onlarla ilişkilendirilmiş Python kodu içerebilir.
Şekil 8.1'e bakın. İçerisinde birkaç nesne olan yeşil bir tepsi gösteriyor. Mavi nesne diğer nesnelere çarpması için onların etrafında hareket etmesini sağlayacak bir Python komut dosyasıyla kontrol ediliyor. Altta gösterilen komut dosyası 2 boyutlu programlarda olan birçok özelliğin aynısına sahip. Bir ana döngü var, x ve y lokasyonlarının listesi var ve vektörü kontrol eden değişkenler var.
Ana program döngüsü Blender tarafından kontrol ediliyor. Listelemede gösterilen Python kodu her seferinde program döngüsü tarafından otomatik olarak çağırılıyor. Bu Python kodunun neden bir ana döngü göstermediğini açıklıyor. Ama ne olursa olsun bir döngü var.
Mavi nesne x,y,z formatında tutulan bir konuma sahiptir. blueobject.position değişkeni kullanılarak değiştirilebilir ve ona erişilebilir. Dizi konumu olan [0] x'in, [1] y'nin ve [2] z'nin konumunu tutar.
change_x ve change_y değişkenlerini bu değiştiricide 2 boyutlu örneklerde kullanmak yerine, bu Blender örneği blueObject["x_change"] ve blueObject["y_change"] kullanıyor.
if yapıları mavi nesnenin ekranın kenarlarına ulaşıp ulaşmadığını ve böylece yönünün tersine çevrilip çevrilmeyeceğini kontrol etmekte kullanılıyor. 2 boyutlu oyunlarda olanın aksine, nesnelerin yerleri ondalıklı sayı türünde (floating point number type) olabilir. Bir öğeyi 5 ve 6 arasında bir yere konumlandırmak için, konumunu 5.5 olarak atamak mümkündür.
Bunun oyun koluyla (Ç.N nam-ı diğer joystick) etkileşime izin verecek şekilde genişletilmesi oldukça kolaydır ve bu kitapta daha sonra anlatılacaktır.
import bge # Mavi nesneye bir referans alalım cont = bge.logic.getCurrentController() blueObject = cont.owner # Mavi nesnenin x ve y koordinatlarını ekrana bastıralım print (blueObject.position[0],blueObject.position[1] ) # x ve y koordinatlarını x_change ve y_change'e göre # değiştir. x_change ve y_change mavi nesneyle ilişkili # oyun özellikleridir. blueObject.position[0]+=blueObject["x_change"] blueObject.position[1]+=blueObject["y_change"] # Nesnenin köşeye gidip gitmediğini kontrol et. # Eğer gittiyse yönü tersine çevir. Bunu 4 köşe için de yap. if blueObject.position[0] > 6 and blueObject["x_change"] > 0: blueObject["x_change"] *= -1 if blueObject.position[0] < -6 and blueObject["x_change"] < 0: blueObject["x_change"] *= -1 if blueObject.position[1] > 6 and blueObject["y_change"] > 0: blueObject["y_change"] *= -1 if blueObject.position[1] < -6 and blueObject["y_change"] < 0: blueObject["y_change"] *= -1
Blender şuradan indirilebilir:
http://www.blender.org/
The file that was demonstrated in the video can be downloaded Videoda gösterilen dosya buradan indirilebilir.
8.4 Tekrar
Çoktan seçmeli test sınavı için burayı tıklayın.
You are not logged in. Log in here and track your progress.
English version by Paul Vincent Craven
Spanish version by Antonio Rodríguez Verdugo
Russian version by Vladimir Slav
Turkish version by Güray Yildirim
Portuguese version by Armando Marques Sobrinho and Tati Carvalho
Dutch version by Frank Waegeman
Hungarian version by Nagy Attila
Finnish version by Jouko Järvenpää
French version by Franco Rossi
Korean version by Kim Zeung-Il
Chinese version by Kai Lin