28
Kas

Bu dersimizde simülasyonumuzu geliştirmeye devam ediyoruz.

Düşen topların bir engelle karşılasmasını sağlayacağız.

def sabit_cizgi_ekle(space):
    govde = pymunk.Body(pymunk.inf, pymunk.inf)
    govde.position = (300,200)
    l1 = pymunk.Segment(govde, (-200, 0), (200.0, 0.0), 5.0)
    l2 = pymunk.Segment(govde, (-200.0, 0), (-200.0, 50.0), 5.0)
    l3 = pymunk.Segment(govde, (200.0, 0), (200.0, 50.0), 5.0)

    space.add_static(l1, l2,l3)
    return l1,l2,l3

def to_pygame(p):
    """pymunk-pygame koordinat düzenlemesi yapar."""
    return int(p.x), int(-p.y+600)

def cizgileri_ciz(ekran, cizgiler):
    for cizgi in cizgiler:
        body = cizgi.body
        pv1 = body.position + cizgi.a.rotated(body.angle)
        pv2 = body.position + cizgi.b.rotated(body.angle)
        p1 = to_pygame(pv1)
        p2 = to_pygame(pv2)
        pygame.draw.line(ekran, THECOLORS["red"], p1, p2)

sabit_cizgi_ekle() fonksiyonuna yine space adında bir parametre veriyoruz. Fonksyionumuzda bir gövde tanımladık ve kütlesiyle momentini pymunk.inf değişkeniyle sonsuz yaptık. Bir nevi duvara monteleme işlemide denebilir sanırım… Gövdemizin pozisyonunu vektörel olarak 300×200 olarak belirledik. l1, l2, l3 değişkenlerine Segment nesnesi tanımladık. İlk parametreyle gövdesini diğer iki parametresini pygame.draw.line() da gördüğümüz gibi çizgi koordinatlarını belirledik. Son koordinat ise çizginin çapını belirliyor; daha doğrusu kalınlığı diyebiliriz…

Sabit olarak ekleyeceğimiz nesneleri Space sınıfımızın add_static() methodu ile ekliyoruz ve fonksiyonumuzda bu şekilde ekledikten sonra fonksiyonumuzun bu çizgileri döndürmesini sağladık.

cizgileri_ciz() fonksiyonuna, çizgileri çizeceği yüzeyi belirtmek için ekran parametresiyle; sabit_cizgi_ekle() fonksiyonundan dönen Segment nesnelerini grafik olarak çizdirmek için de cizgiler parametresini ekledik. Çizgileri bir for döngüsü yardımıyla tek tek pygame.draw.line() ile ekrana çizdirilmesini sağladık. pv1 ile pv2 de çizgilerin Space deki pozisyonlarını ayarladık. rotated(body.angle) da ise çizgilerin bir açısı varsa ona göre bir düzenleme yapılması sağlanıyor. Eğer bir çizgi 45 derece aksi yöne yatıksa Vektörde o kısımın değeri artış ya da azalış gösterecektir.

p1 ve p2 de ise önceki dersimizde pygame’e özgü koordinat çevirme işlemi yapılıyor. Bu çevrimi yapılmış koordinatlar çizginin simülasyondaki yerine göre çizilmesini sağlıyor.

#-*- coding: utf-8 -*-
import sys
import pygame
from pygame.color import *
import pymunk

#def top_ekle(space):
#def top_cizdir(ekran, top):
# Yer kaplamaması için bu şekilde gösterildi. Siz kodunuzu olduğu gibi bırakın.

def sabit_cizgi_ekle(space):
    govde = pymunk.Body(pymunk.inf, pymunk.inf)
    govde.position = (300,200)
    l1 = pymunk.Segment(govde, (-200, 0), (200.0, 0.0), 5.0)
    l2 = pymunk.Segment(govde, (-200.0, 0), (-200.0, 50.0), 5.0)
    l3 = pymunk.Segment(govde, (200.0, 0), (200.0, 50.0), 5.0)
    space.add_static(l1, l2,l3)
    return l1,l2,l3

def to_pygame(p):
    """pymunk-pygame koordinat düzenlemesi yapar."""
    return int(p.x), int(-p.y+600)

def cizgileri_ciz(ekran, cizgiler):
    for cizgi in cizgiler:
        body = cizgi.body
        pv1 = body.position + cizgi.a.rotated(body.angle)
        pv2 = body.position + cizgi.b.rotated(body.angle)
        print cizgi.a.rotated(1.0), cizgi.b.rotated(0.0)
        p1 = to_pygame(pv1)
        p2 = to_pygame(pv2)
        pygame.draw.line(ekran, THECOLORS["red"], p1, p2)

pygame.init()
ekran = pygame.display.set_mode((600, 600))
saat = pygame.time.Clock()

space = pymunk.Space()
space.gravity = (0.0, -900.0)

cizgiler = sabit_cizgi_ekle(space)
toplar = []

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            sys.exit()
        if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
            top_sekli = top_ekle(space)
            toplar.append(top_sekli)
            pass

    ekran.fill(THECOLORS["white"])
    for top in toplar:
        top_cizdir(ekran, top)
    cizgileri_ciz(ekran, cizgiler)
    space.step(1/60.0)
    pygame.display.flip()
    saat.tick(60)

Örnekteki kodda cizgiler değişkenine sabit çizgilerin listesini tutturduk ve oyun döngümüzde cizgileri_ciz() fonksiyonumuza bu değişkeni parametre olarak vererek çizgilerimizi ekrana çizilmesini sağladık. Şimdi bu kodu çalıştırdığınızda bir hata yapmadıysanız fare tıklamalarınızda tepsi gibi bir alana top doldurabilirsiniz.

Şimdi sabit duran bu çizgileri bir pervanenin kanadı gibi bir noktasından iğneleyelim. Bunun için sabit_cizgi_ekle() fonksiyonunun adını cizgi_ekle() olarak değiştiriyoruz ve

def cizgi_ekle(space):
    devir_govdesi = pymunk.Body()
    devir_govdesi.position = (300,200)
    govde = pymunk.Body(50, 10000)
    govde.position = (300,200)
    l1 = pymunk.Segment(govde, (-200, 0), (200.0, 0.0), 5.0)
    l2 = pymunk.Segment(govde, (-200.0, 0), (-200.0, 50.0), 5.0)
    devir_eklemi = pymunk.PinJoint(govde, devir_govdesi, (0,0), (0,0))
    space.add(l1, l2, govde, devir_eklemi)
    return l1,l2

bu şekilde bir kod ortaya çıkarıyoruz… İlk olarak devir_govdesi adında yeni bir Body nesnesi oluşturuyoruz ve diğer Body nesnemizle aynı pozisyona getiriyoruz. Çizgileri tutan gövdemiz artık sabit olmayacağı için 50 kütleli ve 10000 momente sahip oluyor. Sağ taraftaki l3 çizgisinide çıkarıyoruz.

devir_eklemi adında bir PinJoint nesnesi oluşturduk. Bunu bir çubuğun ortasına saplanmış iğne gibi düşünebilirsiniz. PinJoint sınıfının ilk iki parametresi a ve b noktaları olmak üzere koordinat verisi alır; diğer iki parametree farklı bir değer vermeyecekseniz yazmanıza gerek yoktur. Hakkında pek bilgim yok; onun için rasgele değerler vererek ne işe yaradığını çıkartabilirsiniz.

Space sınıfının add_static() methodu yerine de add() methodunu kullandığımıza dikkat edin…

Son olarak şu satırı

cizgiler = sabit_cizgi_ekle(space)

şu şekilde değiştiriyoruz:

cizgiler = cizgi_ekle(space)

Kodumuzu çalıştırıp fare sol tuşuyla top oluşturarak topun çizgilere temas etmesiyle çizgilerin pervane gibi döndüğünü göreceksiniz. Tabii ki; bunu bu şekilde bırakmayacağız. Pervane gibi dönmesini engelleyip kısıtlı olarak sağ-sol aşağı doğru eğilmesini sağlayacağız.

def cizgi_ekle(space):
    devir_govdesi = pymunk.Body()
    devir_govdesi.position = (300,200)
    sinirli_devir_govdesi = pymunk.Body()
    sinirli_devir_govdesi.position = (200,200)
    govde = pymunk.Body(50, 10000)
    govde.position = (300,200)
    l1 = pymunk.Segment(govde, (-200, 0), (200.0, 0.0), 5.0)
    l2 = pymunk.Segment(govde, (-200.0, 0), (-200.0, 50.0), 5.0)
    devir_eklemi = pymunk.PinJoint(govde, devir_govdesi, (0,0), (0,0))
    eklem_siniri = 25
    sinirli_devir_eklemi = pymunk.SlideJoint(govde, sinirli_devir_govdesi, (-100,0), (0,0), 0, eklem_siniri)
    space.add(l1, l2, govde, devir_eklemi, sinirli_devir_eklemi)
    return l1,l2

Fonksiyonumuz biraz daha gelişti… sinirli_devir_govdesi adında yeni bir Body nesnesi tanımladık ve 200×200 pozisyonuna ayarladık. sinirli_devir_eklemi adında ise SlideJoint nesnesi tanımladık. İlk iki parametre PinJoint sınıfındaki gibidir. Üç ve dördüncü parametrelerde PinJoint sınıfının son iki parametresiyle aynı işleve sahiptir. parametre adı anchor olduğundan en uygun anlamı çapa oluyor. Buna göre x koordinatı -100 olan yere çapa atılmış oluyor. Belgelendirme yeterli düzeyde olmadığından ancak bu kadarı çıktı malesef… Son parametre eklem_siniri ise çizginin ne kadar kaydırılılabileceğini(?) söylüyor. Buna da farklı değerler vererek pekiştirme yapabilirsiniz. Son olarakta Space nesnemizin add() methoduna SlideJoint nesnemizi ekliyoruz. Fonksiyonla işimiz burada bitiyor…

Önceki derste listeye eklenen topların ekranda olmamasına rağmen listede yer işgal ettiğini ve bunlarında programın ekrana çizmeye çalıştığını söylemiştik. Ekleyeceğimiz tek satır kod ile y koordinatı sıfırın altına düşen topları listeden çıkartacağız ve olası şişme ve performans sorununun önüne geçeceğiz.

for top in toplar:
    top_cizdir(ekran, top)

Oyun döngümüzdeki bu for döngüsüne

if top.body.position.y < 0: toplar.remove(top)

kodunu ekleyerek

for top in toplar:
    if top.body.position.y < 0: toplar.remove(top)
    top_cizdir(ekran, top)

Bu şekle getiriyoruz. Artık kodumuz sağlıklı bir şekilde çalışmalı. Kodumuzun son hali şu şekilde:

#-*- coding: utf-8 -*-
import sys
import pygame
from pygame.color import *
import pymunk

def top_ekle(space):
    kutle = 1
    yaricap = 24
    eylemsizlik = pymunk.moment_for_circle(kutle, 0, yaricap)
    govde = pymunk.Body(kutle, eylemsizlik)
    pos = pygame.mouse.get_pos()
    govde.position = pos[0], 600-pos[1]
    sekil = pymunk.Circle(govde, yaricap)
    space.add(govde, sekil)
    return sekil

def top_cizdir(ekran, top):
    p = int(top.body.position.x), 600-int(top.body.position.y)
    pygame.draw.circle(ekran, THECOLORS["blue"], p, int(top.radius), 0)

def cizgi_ekle(space):
    devir_govdesi = pymunk.Body()
    devir_govdesi.position = (300,200)
    sinirli_devir_govdesi = pymunk.Body()
    sinirli_devir_govdesi.position = (200,200)
    govde = pymunk.Body(50, 10000)
    govde.position = (300,200)
    l1 = pymunk.Segment(govde, (-200, 0), (200.0, 0.0), 5.0)
    l2 = pymunk.Segment(govde, (-200.0, 0), (-200.0, 50.0), 5.0)
    devir_eklemi = pymunk.PinJoint(govde, devir_govdesi, (0,0), (0,0))
    eklem_siniri = 25
    sinirli_devir_eklemi = pymunk.SlideJoint(govde, sinirli_devir_govdesi, (-100,0), (0,0), 0, eklem_siniri)
    space.add(l1, l2, govde, devir_eklemi, sinirli_devir_eklemi)
    return l1,l2

def to_pygame(p):
    return int(p.x), int(-p.y+600)

def cizgileri_ciz(ekran, cizgiler):
    for cizgi in cizgiler:
        body = cizgi.body
        pv1 = body.position + cizgi.a.rotated(body.angle)
        pv2 = body.position + cizgi.b.rotated(body.angle)
        p1 = to_pygame(pv1)
        p2 = to_pygame(pv2)
        pygame.draw.line(ekran, THECOLORS["red"], p1, p2)

pygame.init()
ekran = pygame.display.set_mode((600, 600))
saat = pygame.time.Clock()

space = pymunk.Space()
space.gravity = (0.0, -900.0)

cizgiler = cizgi_ekle(space)
toplar = []

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            sys.exit()
        if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
            top_sekli = top_ekle(space)
            toplar.append(top_sekli)
            pass

    ekran.fill(THECOLORS["white"])
    for top in toplar:
        if top.body.position.y < 0: toplar.remove(top)
        top_cizdir(ekran, top)
    cizgileri_ciz(ekran, cizgiler)

    space.step(1/60.0)
    pygame.display.flip()
    saat.tick(60)

Ne yazık ki pymunk hakkında pek fazla belge yok ve Kaynak altında verdiğim linkler ne kadar yeterli olur bilemiyorum, ama İngilizcesi yeterli olanlar sınıf isimlerinden vs. öğrenmekte zorluk çekmeye bilirler. Bende bu yazıyı yazarken bu modülü öğrendiğim için sorularınıza cevap veremezsem kusuruma bakmayın...

Kaynak:

http://code.google.com/p/pymunk/wiki/SlideAndPinJointsExample

http://pymunk.googlecode.com/svn/trunk/docs/api/index.html

Bu yazı Creative Commons-BY-SA ile lisanslanmıştır. Bu yazıyı ilk sahibini belirtmek ve aynı lisansla dağıtmak koşuluyla kullanabilirsiniz.

Benzer Yazılar:

  1. pymunk 2B Fizik Kütüphanesi – Bölüm 1
  2. Pygame ile Oyun Programlama – Sprite 1. Bölüm
26
Kas

pymunk kullanımı basit 2 boyutlu oyunlar için hazırlanmış 2B fizik motorudur. Bu modül chipmunk üzerine inşa edilmiştir. pymunk’u pygame, pyglet, PySFML gibi oyun kütüphaneleriyle kullanabileceğiniz gibi PyQt gibi grafik arayüz kütüphaneleriyle de kullanabilirsiniz.

pymunk modülünü öğrenirken pygame modülünden faydalanacağız…

pymunk ile daire, dikdörtgen ve çokgen şekilleri fizik kurallarına uydurabileceğimiz sınıflar ile eklem oluşturmak, engel oluşturmak gibi işlemler için de sınıflar mevcuttur.

pymunk modülünü; GNU/Linux kullanıcıları python-setuptools paketini depolarından kurduktan sonra “easy_install pymunk” ya da “easy_install pip” dedikten sonra “pip install pymunk” komutunu vererek kurabilir, Windows kullanıcıları ise buradan uygun buldukları setup dosyasını indirerek kurabilirler. Tabii GNU/Linux kullanıcıları komutları verirken yönetici yetkisi almalıdır. Yani komutunuzun başına “sudo” komutunu eklemelisiniz…

Kurulum tamamlandıktan sonra Python yorumlayıcısına

import pymunk

yazarak test edebilirsiniz. Eğer ImportError hatası almıyorsanız sorun yok demektir. O zaman motoru çalıştıralım :)

pymunk’ta fizik kurallarını uygulayacağımız bir alan oluşturmamız gereklidir. Bu işi Space() sınıfı ile yapıyoruz. Daha sonra gravity özelliği ile yer çekiminin uygulanacağı yönü belirliyoruz…

import sys
import pygame
from pygame.color import *
import pymunk

pygame.init()
ekran = pygame.display.set_mode((600, 600))
saat = pygame.time.Clock()

space = pymunk.Space()
space.gravity = (0.0, -900.0)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            sys.exit()

    ekran.fill(THECOLORS["white"])
    space.step(1/60.0)
    pygame.display.flip()
    saat.tick(60)

Örnekte görüldüğü gibi space değişkenine Space sınıfımızı atadık ve gravity özelliğine (0.0, -900.0) olarak atadık. İster bu şekilde yazalım, ister pymunk.Vec2d(0.0, -900.0) yazalım fark etmez. Sınıfımız doğru şekilde girilen veriyi kendisi Vec2d vektör nesnesine dönüştürecektir.

gravity özelliğine girilen ilk değer X koordinatını, ikincisi ise Y koordinatını temsil eder. Artı değer verilirse X için sağa, Y için yukarı doğru yer çekimi oluşur. Eksi değer girilirse tersi yönlere yer çekimi oluşur. Tabii yer çekimine maruz kalan nesnelerin vektörel değer girdiğimizden pygame koordinat tarzını ona göre ayarlamak gerekir.

Oyun döngümüzde 60 fps olarak ayarladığımız döngü sayısını fizik hesaplama süresiyle eşit tutuyoruz. step() methoduna girdiğimiz değerde oyun döngüsüyle eşit hesaplama yapmasını sağlıyor. Burada amaç simülasyonun uyumlu olmasını sağlamaktır.

Alanımızı oluşturduğumuza göre şimdi geometrik şekilleri çizdirmeye çalışabiliriz…

İlk olarak fare imleciyle ekrana tıkladığımızda bir daire çizdirelim ve fizik kurallarına göre yer çekimiyle aşağı doğru hareket etmesini sağlayalım…

def top_ekle(space):
    kutle = 1
    yaricap = 24
    eylemsizlik = pymunk.moment_for_circle(kutle, 0, yaricap)
    govde = pymunk.Body(kutle, eylemsizlik)
    pos = pygame.mouse.get_pos()
    govde.position = pos[0], 600-pos[1]
    sekil = pymunk.Circle(govde, yaricap)
    space.add(govde, sekil)
    return sekil

def top_cizdir(ekran, top):
    p = int(top.body.position.x), 600-int(top.body.position.y)
    pygame.draw.circle(ekran, THECOLORS["blue"], p, int(top.radius), 0)

top_ekle ve top_cizdir adında iki fonksiyon yazdık. top_ekle fonksiyonundan başlayalım:

Çizdireceğimiz şekle göre bir moment hesabı yapılması gerekiyor. Daire çizdireceğimiz zaman moment_for_circle fonksiyonunu dairenin moment hesabını yapmak için kullanırız. Değişken adlarından anlayacağınız gibi ilk parametresine kütle değerini, üçüncü parametresine de dairenin yarıçapını giriyoruz. 0 olan ikinci parametre ise dairenin iç yarıçapını temsil ediyor. Yani delikli para gibi bir şey düşünüyorsanız ikinci parametreye yarıçap verebilirsiniz.

Oluşturacağımız şekiller Body adında bir gövdeye ait olmalıdırlar. Body nesnemizi oluştururken şeklimizin momentinden ve kütlesinden haberdar olmasını sağlıyoruz. Sonra da çizileceği an gelince fare imleci pozisyonuna göre, ama y ekseni ekran yüksekliğinden çıkartılarak çizilmesi sağlanıyor. Çünkü matematikten hatırlarsanız y ekseni aşağı doğru eksilere inerken pygame de aşağı doğru artar. Bunu tersine çevirmek için böyle bir şey yapıyoruz.

Body nesnemiz ve yarıçap bilgisiyle bir Circle nesnesi oluşturuyoruz ve space parametresinden yararlanarak Space nesnemize gövdemizi ve şeklimizi ekliyoruz. Fonksiyonumuz bize Circle nesnemizi döndürüyor…

top_cizdir fonksiyonumuza ise ekran ve top parametrelerini almasını sağlıyoruz. p değişkeninde pygame’in anlayacağı koordinat verisini ayarlıyoruz ve draw.circle() fonksiyonumuz ile ekrana mavi renkli ve çapı 48 pixel olan bir daire çizilmesini sağlıyoruz.

Şimdi de ana kodumuza ufak eklemeler yaparak tam kodu yazalım.

import sys
import pygame
from pygame.color import *
import pymunk

def top_ekle(space):
    kutle = 1
    yaricap = 24
    eylemsizlik = pymunk.moment_for_circle(kutle, 0, yaricap)
    govde = pymunk.Body(kutle, eylemsizlik)
    pos = pygame.mouse.get_pos()
    govde.position = pos[0], 600-pos[1]
    sekil = pymunk.Circle(govde, yaricap)
    space.add(govde, sekil)
    return sekil

def top_cizdir(ekran, top):
    p = int(top.body.position.x), 600-int(top.body.position.y)
    pygame.draw.circle(ekran, THECOLORS["blue"], p, int(top.radius), 0)

pygame.init()
ekran = pygame.display.set_mode((600, 600))
saat = pygame.time.Clock()

space = pymunk.Space()
space.gravity = (0.0, -900.0)

toplar = []

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
            sys.exit()
        if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
            top_sekli = top_ekle(space)
            toplar.append(top_sekli)

    ekran.fill(THECOLORS["white"])
    for top in toplar:
        top_cizdir(ekran, top)
    space.step(1/60.0)
    pygame.display.flip()
    saat.tick(60)

Evet toplar adında boş bir liste oluşturduk ve ekranda fare sol tuşuyla bastığımızda şeklimizin oluşmasını ve toplar listesine eklenmesini sağladık. Oyun döngümüzde ise listeye eklenen her topun sırayla çizilmesini sağladık. Kodu çalıştırıp topları sol fare tuşuyla oluşturmaya başladıktan sonra subliminal mesaj gibi mavi topların belirip kaybolduğunu görebilirsiniz. Bu durum ya modüllerden kaynaklanan bir durum ya da listeye eklenen ama ekrandan çıkmış toplarında çizilmeye çalışmasından kaynaklı olabilir. Bir sonraki devam dersimizde bu konuyuda halletmeye çalışacağız…

Bu yazı Creative Commons-BY-SA ile lisanslanmıştır. Bu yazıyı ilk sahibini belirtmek ve aynı lisansla dağıtmak koşuluyla kullanabilirsiniz.

Benzer Yazılar:

  1. Pygame ile Oyun Programlama – Sprite 1. Bölüm
  2. Pygame ile Oyun Programlama – Sprite 2. Bölüm
  3. Pygame ile Oyun Programlama – Sprite 3. Bölüm
16
Ağu

pygame.rect modülünde kullandığımız çarpışma kontrolünü pygame.sprite modülünün sağladıklarıyla daha etkili bir şekilde yönetebiliriz. Sprite nesneleri kullandığımız için bu araçları kullanırken Sprite ve gruplarını kullanmış olacağız.

Dikdörtgensel bir Sprite nesnesinin başka bir Sprite nesnesi ile çarpışmasını collide_rect fonksiyonu ile kontrol edebiliriz.

pygame.sprite.collide_rect(Sprite1, Sprite2)

Çarpışma varsa bu fonksiyon geriye True değeri döndürecektir. Aksi halde False değerini döndürecektir.

Dairesel Sprite nesnelerinin çarpışma kontrolünü ise collide_circle() fonksiyonu ile kontrol ediyoruz. Bu fonksiyonuda collide_rect() fonksiyonu ile aynı şekilde kullanıyoruz…

Bu iki fonksiyon ile bir Sprite ın olağan rect değerine göre kontrol sağlanıyor. Eğer bir Sprite nesnesinin çarpışma alanını genişletmek isterseniz collide_rect_ratio ile collide_circle_ratio sınıflarını kullanmalısınız…

pygame.sprite.collide_rect_ratio(2.0)(Sprite1, Sprite2)
pygame.sprite.collide_circle_ratio(1.5)(Sprite1, Sprite2)

Bu sınıflar ilk verilen Sprite nesnesinin dikdörtgensel alanını ya da dairesel olarak çapını değiştirmenizi ve bu yeni değerlerle çarpışma kontrolünü yapmanızı sağlar. Bu sınıfların kullanımı size garip gelebilir, eğer gelirse şu yöntemi kullanarak daha anlaşılır kılabilirsiniz.

collide_rect = pygame.sprite.collide_rect_ratio(2.0)
collide_rect(Sprite1, Sprite2)

collide_circle = pygame.sprite.collide_circle_ratio(1.5)
collide_circle(Sprite1, Sprite2)

Bu şekilde olmasını bu sınıfların __call__ methodu sağlıyor. Nasıl __init__ methodu sınıf başlatılınca çalışıyorsa, __call__ methodu ise bu şekilde çalışıyor…

Burada verilen float değerlere bakarsak 2.0 değeri dikdörtgen alanın iki katına çıakrtır. Eğer -1.0 verirseniz aynı değerde kalır, 0.5 ise yarıya düşürür. Bu oranlara göre istediğiniz gibi Sprite nesnenize görünmez bir alan sağlıyabilirsiniz. Örnek olarak radar alanı verilebilir…

groupcollide fonksiyonu ise iki Sprite grubu nesnesinin çarpışmalarını kontrol ediyor. Ve gerekli parametre verilirse çarpışan grupların elemanlarını sildirebiliyorsunuz…

pygame.sprite.groupcollide(grup1, grup2, True, False)

Parametre olarak iki grup girdik. Üçüncü parametre ile grup1 in elemanları çarpışınca silinecek, dördüncü parametrenin False olmasıyla grup2 nin elemanları silinmeyecektir. Bu fonksiyon ile Kamikaze Saldırısı adında bir oyun yapabilirsiniz :)

Son fonksiyonumuz ise spritecollide(). Bu fonksiyon ile de bir Sprite ın, bir sprite grubuna temas etmesini kontrol ediyoruz.

pygame.sprite.spritecollide(sprite, grup, True)

Bu kod ile sprite a temas eden grup üyeleri True parametresi sayesinde yok olacaktır. Eğer False verirseniz spritecollide() fonksiyonu çarpışan Sprite nesnelerini liste olarak döndürecektir…

pygame.sprite modülünde bulunan bu fonksiyon ve sınıfları öğrenerek Sprite derslerinin sonuna gelmiş olduk. Bundan sonra neler olacağını zaman gösterecek…

Yazım hatası varsa bildiriniz.
Bu yazı Creative Commons-BY-SA ile lisanslanmıştır. Bu yazıyı ilk sahibini belirtmek ve aynı lisansla dağıtmak koşuluyla kullanabilirsiniz.

Benzer Yazılar:

  1. Pygame ile Oyun Programlama – Sprite 1. Bölüm
  2. Pygame ile Oyun Programlama – Sprite 2. Bölüm
  3. Pygame ile Oyun Programlama – Sprite 3. Bölüm
  4. Pygame ile Oyun Programlama – Image Modülü
  5. Pygame ile Oyun Programlama – Font Modülü
13
Ağu

Sprite gruplamaya yarayan Group sınıfının bir dezavantajı var dedik, ancak dezavantaj yerine bir eksiklik diyebiliriz. Daha doğrusu, kullanım alanına göre farklı diyebiliriz.

Group sınıfının draw() methoduyla Sprite nesnelerimizi parametre olarak verdiğimiz yüzeye çizdiriyorduk. Bu method bize None döndürür.

Bu sınıfın clear() methodu ise Sprite ın çizildiği alanı temizliyordu. Biz bu yöntemle belli koordinatları temizleyerek performans sağlıyorduk. Aynı şekilde; tüm ekranı güncellemek yerine, çizdirdiğimiz dikdörtgen alanları güncelleyerek biraz daha performans artışı sağlayabiliriz.

Yeni Sprite gruplama sınıfımız RenderUpdates, çizim yaptığımız alanları güncellemekte yardımcı olacaktır. Bu sınıfın draw() methodu geriye bir Rect listesi döndürür. Bu listedeki Rect nesneleri ekrana çizilen Spriteların çizildiği alanı göstermektedir. pygame.display modülünün update() methoduyla da parametre olarak vereceğimiz bu Rect listesiyle update() methodu verilen dikdörtgen alanları güncelleyecektir.

import pygame, sys
from asker import *
pygame.init()

pencere = pygame.display.set_mode((500,500))
temizle = pygame.Surface((500,500))

grup = pygame.sprite.RenderUpdates()

asker1 = Asker((100,100))
asker2 = Asker2((200,100))

grup.add(asker1, asker2)

saat = pygame.time.Clock()
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    grup.clear(pencere, temizle)

    grup.update()
    rectlist = grup.draw(pencere)
    pygame.display.update(rectlist)
    saat.tick(24)

Yukarıdaki örnek açıkladığım şekilde çalışmaktadır. Tabii görüntü olarak bu performans artışını algılayamıyoruz, ama çok fazla iş yapan ve çizim yapan bir kodunuz varsa gözle görülür bir performans artışı olacaktır.

RenderUpdates, Group sınıfını genişleten(miras alan) bir sınıftır. Farkı ise draw() methodunun geriye Sprite nesnelerinin, Rect bilgilerini liste olarak döndürmesidir.

RenderUpdates sınıfı Group sınıfını genişlettiği için Group sınıfında bulunan methodları da kullanabilmektedir…

Python da bilindiği üzere sözlükler sırasız veri tipidir. Örneğin;

sozluk = {"ali":18, "mehmet":22, "dilek":19}

gibi bir sözlük oluşturup print deyimi ile çıktısını aldığınızda yazdığınız sıra da olmadığını göreceksiniz. Sözlüklerin anahtarları 1,2,5,3 gibi sayılardan oluşuyorsa ne kadar karışık sırayla versenizde 1,2,3,5 gibi sıralanacaktır. Ancak buna güvenerek iş yapmayınız…

RenderUpdates ve Group sınıfları Sprite nesnelerini sözlükte tutar ve sırasız olarak ekrana çizer. Bu durum oyun ekranınızda sıralı bir çizim gerektiğinde sıkıntıya yol açabilir(Harita çiziminde yer ile yerin üstünde durması gereken bir ağacın yerden önce çizilmesi gibi.). Bunun önüne geçmek için sıralı çizim yapan OrderedUpdates sınıfını kullanmalıyız. Bu sınıfın RenderUpdates sınıfından tek farkı Sprite nesnelerini sözlük yerine listede tutmasıdır. Bunun dışında RenderUpdates sınıfında kullandığınız her methodu bu sınıfla da kullanabilirsiniz.

Bu sınıfın draw() methodu da Rect listesi döndürdüğü için performans sağlamaya yardımcı olur.

Son Sprite gruplama sınıfımız ise LayeredUpdates…

Bu sınıf diğer Sprite gruplama sınıflarına göre daha çok özellik sunar. Bir resim düzenleme programında nasıl katmanlarla çalışıyorsanız bu sınıfla da Sprite nesnelerini katmanlara bölebiliyorsunuz. LayeredUpdates de varsayılan katman 0(sıfır)dır. add() methodu ile eklediğiniz her Sprite 0 katmanına eklenir. Eğer yeni bir katmana Sprite eklemek isterseniz şu şekilde yapabilirsiniz.

import pygame, sys
from asker import *
pygame.init()

pencere = pygame.display.set_mode((500,500))
temizle = pygame.Surface((500,500))

grup = pygame.sprite.LayeredUpdates()

asker1 = Asker((100,100))
asker2 = Asker2((200,100))

grup.add(asker1)
grup.add(asker2, layer=1)

saat = pygame.time.Clock()
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    grup.clear(pencere, temizle)
    grup.update()
    rectlist = grup.draw(pencere)
    pygame.display.update(rectlist)
    saat.tick(24)

asker2 adındaki Sprite nesnemiz 1(bir) katmanına eklenecektir. LayeredUpdates sınıfının layers() methodunu print ile yazdırarak katmanları görebilirsiniz.

Üstteki duruma göre çıktımız böyle olur:

print grup.layers

[0, 1]

Rect sınıfını anlattığım konuda, fare imleci konumuyla nasıl nesnelerle çarpışma kontrolünü denetlediğimizi öğrendik. LayeredUpdates sınıfı da get_sprites_at() methodu ile parametre olarak verdiğimiz koordinatta hangi Spritelar çizili ise bir listesini döndürür. Bu özellik sayesinde hayal gücünüzü kullanarak bir çok şey yapabilirsiniz. Örneğin(1. bölümün sonunda verdiğim dosyayı indirerek asker.py dosyasını elde edebilirsiniz):

import pygame, sys
from asker import *
pygame.init()

pencere = pygame.display.set_mode((500,500))
temizle = pygame.Surface((500,500))

grup = pygame.sprite.LayeredUpdates()

asker1 = Asker((100,100))
asker2 = Asker2((200,100))

grup.add(asker1)
grup.add(asker2, layer=1)

saat = pygame.time.Clock()
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    for i in grup.get_sprites_at(pygame.mouse.get_pos()):
        i.rect.y += 5
    grup.clear(pencere, temizle)
    grup.update()
    rectlist = grup.draw(pencere)
    pygame.display.update(rectlist)
    saat.tick(24)

Oyun döngümüzde bu methodu kullandık ve pozisyon parametresine fare imlecinin konumunu verdik. Bir for döngüsü ile fare imlecinin temas ettiği nesnelerin 5px aşağı doğru inmesini sağladık. Örnek kodu çalıştırdığınızda fare imlecinin konumuna göre askerlerin yüksekliği değişecektir.

Bir Sprite ın bulunduğu katmanı değiştirmek isteyebilirsiniz. Bunun sebebi fare imlecinin temas ettiği Sprite nesnesini öne almak olabilir. Bunu change_layer() methodu ile gerçekleştirebiliriz. Askerlerimizi bir biri üzerine gelecek şekilde çizdirelim ve bu methodu kullanarak fare imlecinin temas ettiği Sprite ı öne getirelim.

import pygame, sys
from asker import *
pygame.init()

pencere = pygame.display.set_mode((500,500))
temizle = pygame.Surface((500,500))

grup = pygame.sprite.LayeredUpdates()

asker1 = Asker((180,100))
asker2 = Asker2((200,100))
asker3 = Asker2((290,100))

grup.add(asker1)
grup.add(asker2, layer=1)

saat = pygame.time.Clock()
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    for i in grup.get_sprites_at(pygame.mouse.get_pos()):
        grup.change_layer(i, 0)
    grup.clear(pencere, temizle)
    grup.update()
    rectlist = grup.draw(pencere)
    pygame.display.update(rectlist)
    saat.tick(24)

Örnekte Asker nesnelerini birbirine temas edecek şekilde çizdirdik. Bundaki amaç fare imlecini üzerlerine getirince hangi Sprite ın ilk çizildiğini fark edebilmektir. Bu sefer for döngümüzde change_layer() methodunu kullandık ve temas halindeki Sprite nesnesini 0 katmanına aldırdık. Doğal olarak 1 katmanında bulunan Sprite nesnemiz 0 katmanına aktarılınca 1 katmanı silinmiş olacak. Ayrıca fare imleci her iki Sprite nesnesine de temas ediyorsa sıralamaya göre çizileceği için istediğiniz sonucu alamama ihtimali de olacaktır.

Burada nasıl bir kullanımı olabileceğine değindik. Halbuki bu işi yapan bir method vardır. move_to_front() methodu parametre olarak verdiğiniz Sprite nesnesini en önce alacaktır.

for i in grup.get_sprites_at(pygame.mouse.get_pos()):
    grup.move_to_front(i)

Eğer Sprite nesnesini en arkaya almak isterseniz de move_to_back() methodunu kullanabilirsiniz.

for i in grup.get_sprites_at(pygame.mouse.get_pos()):
    grup.move_to_back(i)

Bu kodu denerken fark ettim ki; fare imleci her iki Sprite a temas ediyorsa çok hızlı olarak her bir nesneyi ard arda arkaya atıyor ve bize sorun olabilecek bir görüntü ortaya çıkıyor. Ayrıca her arkaya atılan Sprite nesnesi en düşük katmandan bir eksi katmana atılıyor(0 ise -1). Bu da sürekli bir işlemde sürekli değişen katman adının -500 lere dayanmasına neden oluyor.

LayeredUpdates sınıfının başka methodları da mevcuttur, ama bunları uygulamalı derslerde gerekli olursa kullanacağız ve bu arada öğrenmiş olacağız. Sprite gruplama sınıfları bu kadar(LayeredDirty var, ama kullanmaya gerek yoktur.). Bir sonraki derste pygame.sprite modülünde bulunan fonksiyonları öğreneceğiz.

Yazım hatası varsa bildiriniz.
Bu yazı Creative Commons-BY-SA ile lisanslanmıştır. Bu yazıyı ilk sahibini belirtmek ve aynı lisansla dağıtmak koşuluyla kullanabilirsiniz.

Benzer Yazılar:

  1. Pygame ile Oyun Programlama – Sprite 2. Bölüm
  2. Pygame ile Oyun Programlama – Sprite 1. Bölüm
  3. Pygame ile Oyun Programlama – Surface Modülü
  4. Pygame ile Oyun Programlama – Rect Modülü
  5. Pygame ile Oyun Programlama – Image Modülü
9
Ağu

İlk Sprite dersinde Sprite sınıfını nasıl kullanacağımızı öğrendik.

Sprite sınıfımızda tanımladığımız self.image ve self.rect niteliğini çağırarak blit işlemini gerçekleştirdik ve update() methoduna; Sprite’ımızın kontrolünü sağlayan kodlarımızı yazdıp, bu methodu oyun döngümüzde çağırdık ve oyun döngümüzün kod bakımından fakirleşmesini sağladık. Ama yine bir problemimiz var…

Yazdığımız oyuna bağlı olarak bir çok Sprite oluşturabiliriz ve hepsinin tek tek update() methodlarını oyun döngümüze yazarak ve tek tek blit ederek kod zenginliğinde kafamızı karıştırabiliriz. Bu gibi bir durumu engellemek için Sprite grupları oluşturmamız gerekir. Pygame bize yeteri kadar gruplama yapmamızı sağlayan sınıf sağlar.

import pygame, sys
from asker import Asker
pygame.init()

pencere = pygame.display.set_mode((500,400))

asker = Asker((250,50))
asker2 = Asker((100,50))
asker3 = Asker((200,150))
asker4 = Asker((50,100))

saat = pygame.time.Clock()
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    pencere.fill((0,0,0))

    asker.update()
    asker2.update()
    asker3.update()
    asker4.update()   

    pencere.blit(asker.image, asker.rect)
    pencere.blit(asker2.image, asker.rect)
    pencere.blit(asker3.image, asker.rect)
    pencere.blit(asker4.image, asker.rect)
    pygame.display.flip()
    saat.tick(24)

Bir önceki derste kullandığımız asker modülünü çağırdık ve dört adet Asker nesnesi oluşturduk. Oluşan kod yığınını gördünüz. Bu yığın Sprite nesnelerinize göre değişiklik gösterecektir.

Group sınıfı en temel Sprite gruplama sınıfıdır.

grup = pygame.sprite.Group(asker,asker2,asker3,asker4)

Tek satır kod ile Sprite grubumuzu oluşturduk istersek Group sınıfının add() methodu ile de spritelarımızı ekleyebiliriz.

grup = pygame.sprite.Group()
grup.add(asker)
grup.add(asker2,asker3,asker4)

Tek tek ekleyebileceğiniz gibi, birden fazla Sprite nesnesini de ekleyebilirsiniz.

Group sınıfının birde update() methodu vardır. Bu method ile gruba eklediğiniz bütün Sprite nesnelerinin update() methodları çalıştırılır. Eğer Sprite sınıfınızda update() methodunuz parametre alıyorsa diğer Sprite sınıflarınızda aynı parametreyi almalıdır ve Group() nesnesini oluşturup update() methodunu kullanırkende bu parametreyi es geçmemeliyiz. Farklı argüman alan methodlarda sorun yaşamanız büyük bir ihtimaldir.

Gruptaki Sprite nesnelere ulaşmak için ise sprites() methodu mevcuttur. Bu method Sprite nesnelerini liste olarak döndürür.

import pygame, sys
from asker import Asker
pygame.init()

pencere = pygame.display.set_mode((500,400))

asker = Asker((250,50))
asker2 = Asker((250,150))

grup = pygame.sprite.Group(asker,asker2)

saat = pygame.time.Clock()
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    pencere.fill((0,0,0))

    grup.update()

    for sprite in grup.sprites():
        pencere.blit(sprite.image, sprite.rect)

    pygame.display.flip()
    saat.tick(24)

Yukarıdaki örnekte Asker nesnemizden iki adet oluşturduk ve Group sınıfı ile Sprite grubu oluşturduk. Group sınıfının update() methodu ile bütün spritelerın update() methodlarını da çalıştırmış olduk. Group sınıfının sprites() methodunu kullanarak bir for döngüsü yardımıyla spritelarımızı ekrana çizdirdik.

Ekrana çizdirme işini daha basite indirgeyebiliriz. sprites() methodunu kullanarak for döngüsüyle çizdirmek ve blit işleminde; her Sprite nesnesinin self.image ve self.rect niteliklerini yazmak fazladan kod satırıdır ve Sprite sınıfınızı genişlettiğinizde self.image niteliği yerine başka isim seçebilirsiniz. Bu da ayrı bir sorun olmaktadır.

Group sınıfının draw() methodu gruptaki her Sprite nesnesini ekrana çizdirir. Biz sadece çizdireceğimiz yüzeyi parametre olarak veririz; gerisini Group nesnemiz hallediyor.

import pygame, sys
from asker import Asker
pygame.init()

pencere = pygame.display.set_mode((500,400))

asker = Asker((250,50))
asker2 = Asker((250,150))

grup = pygame.sprite.Group(asker,asker2)

saat = pygame.time.Clock()
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    pencere.fill((0,0,0))

    grup.update()

    grup.draw(pencere)
    pygame.display.flip()
    saat.tick(24)

Ana yüzeyimizi draw() methoduna parametre olarak verdik ve Group nesnemiz, barındırdığı Sprite nesnelerini daha önceki örneğimizdekine benzer bir yolla ekrana çizdirdi.

Yazdığımız kodlar ilerledikçe kısalmaya başladı. Birazdan bir kaç satır uzayacak, ama bu şekilde daha fazla performans sağlayacağız.

Önceki yazının başında self.image ile self.rect niteliklerinin olması gerektiğini söylemiştim. Sebebi ise Sprite gruplarında, grupların bu nitelikleri çağırmasındandı…

Ana yüzeyimizle aynı boyutta ve renkte bir Surface nesnesi oluşturacağız. Bunun nedeni ise ekrana çizdirdiğimiz Sprite nesnelerinin hareketiyle oluşan kirliliği, Group sınıfının clear() methodunu kullanarak temizleyeceğiz.

Oyun döngümüzde her daim mevcut olan pencere.fill() in yaptığını yapan bu method, çizilen alanı temizlediğinden daha performanslıdır. Bu methodu kullanmak kişinin isteğine kalan bir durum, ama oyununuzu geliştirdikçe bir yavaşlama veya kasma hissettiğinizde aklınızda bulunsun.

import pygame, sys
from asker import Asker
pygame.init()

pencere = pygame.display.set_mode((500,400))
temizle = pygame.Surface((500,400))

asker = Asker((250,50))
asker2 = Asker((250,150))

grup = pygame.sprite.Group(asker,asker2)

saat = pygame.time.Clock()
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    grup.clear(pencere, temizle)

    grup.update()

    grup.draw(pencere)
    pygame.display.flip()
    saat.tick(24)

temizle adında bir Surface nesnesi oluşturduk. Oyun döngümüzde pencere.fill() in yerini alan grup.clear() a ilk parametre olarak ana penceremizin örneğini yazdık. Bu sayede Group nesnemize hangi yüzeyi temizleyeceğini söyledik; ikinci parametre de ise temizle adındaki Surface nesnemizi yazdık. Group nesnemiz, temizle adındaki Surface nesnemizi kullanarak sprite animasyonumuzun önceki hareketindeki konumunu temizleyecektir ve döngü boyunca bu sürecektir.

Merak edenler temizle.fill() ı kullanarak farklı bir renge boyayarak Group nesnesinin temizlediği alanı daha net görebilirler.

Group sınıfının copy() methodunu kullanarak da kendisinden bağımsız kopyasını oluşturabilirsiniz…

Group sınıfının dezavantajı olduğu gibi Spritelarında dezavantajı vardır. Pasif olması gerektiği halde bir Sprite’ın update() methodunu çalıştırarak performans kaybedebilirsiniz. Group sınıfının dezavantajına ise bir sonraki derste konu içinde değineceğim.

Yazım hatası varsa bildiriniz.
Bu yazı Creative Commons-BY-SA ile lisanslanmıştır. Bu yazıyı ilk sahibini belirtmek ve aynı lisansla dağıtmak koşuluyla kullanabilirsiniz.

Benzer Yazılar:

  1. Pygame ile Oyun Programlama – Sprite 1. Bölüm
  2. Pygame ile Oyun Programlama – Surface Modülü
  3. Pygame ile Oyun Programlama – Image Modülü
  4. Pygame ile Oyun Programlama – Rect Modülü
  5. Pygame ile Oyun Programlama – Mixer Modülü
7
Ağu

Sprite terimi anlam olarak peri, hayelet vb. anlamına gelse de konu itibariyle alakasız bir anlamı var.

Sprite 2B oyunlarda kullanılan bağımsız görüntülerdir. Bir sprite tekil ya da birden fazla resimden oluşabilir. Bu resimlerin arka arkaya oynamasıyla animasyon oluşur. Pygame de Sprite kullanmak için pygame.sprite modülünün Sprite sınıfı vardır.

Sprite modülü en az bir Surface ve bir Rect nesnesi içermelidir. Varsayılan olarak self.image niteliği bir Surface, self.rect niteliği de bir Rect nesnesini barındırmalıdır.

Sprite modülü bir sınıftır ve bu sınıfı kullanmak için yeni bir sınıf oluşturup miras almalıyız.

from pygame.sprite import Sprite
import pygame

class Kare(Sprite):
    def __init__(self):
        Sprite.__init__(self)
        self.image = pygame.Surface((100,100))
        self.rect = self.image.get_rect()

En basit Sprite sınıfı bu şekildedir. Bu sınıfı şu şekilde kullanabiliriz.

import pygame, sys
from kare import Kare
pygame.init()

pencere = pygame.display.set_mode((500,400))

kare = Kare()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    pencere.fill((255,255,255))

    pencere.blit(kare.image, kare.rect)
    pygame.display.flip()

Kare sınıfımızı kare.py adıyla kaydettiğimizi varsayarsak yukarıda from kare import Kare ile sınıfımızı çağırmış oluyoruz. kare örneğine Kare sınıfımızı atıyoruz ve ana döngümüzde sınıfımızın self.image niteliğini ve self.rect niteliğini kullanarak ekrana yüzeyimizi çizdiriyoruz.

Sprite sınıfının kullanımı basit ve hızlıdır. Bu hızın nedeni en iyi şekilde optimize edilmesindendir. Çoğu zaman kendi sınıfınızı yazmak yerine Sprite sınıfını miras alarak genişletmeniz yeterlidir.

Sprite ın bir çok avantajı vardır. Genişlettiğiniz sınıfı argüman alacak şekilde ayarlayıp sınıfınızın çeşitli özellikte yüzeyler oluşturmasını sağlayabilirsiniz. Ayrıca Sprite sınıfının methodlarında update() methodu ile oyun döngüsüne yazacağınız onlarca satır kodu bu methoda yazarak döngüde tek satır yer kaplamasını sağlayabilirsiniz. Ve tabii ki update() methoduyla da istediğiniz gibi argüman alabilirsiniz. Sprite sınıfının başka methodları da mevcuttur, ama update() methodu haricindekilerin kullanımına rastlamanız düşük bir ihtimal, ki gerekte yoktur.

Şimdi Kare sınıfımızı geliştirelim:

# kare.py
from pygame.sprite import Sprite

class Kare(Sprite):
    def __init__(self, renk, konum):
        Sprite.__init__(self)
        self.image = pygame.Surface((100,100))
        self.image.fill(renk)
        self.rect = self.image.get_rect()
        self.rect.x, self.rect.y = konum

Kare sınıfımıza renk ve konum adında iki tane parametre ekledik ve renk parametresinin değerini self.image.fill() e atadık. konum adlı parametrenin değerini ise rect nesnemizin x ve y niteliğine atadık. Biz renk parametresinden üç elemanlı bir tuple, konum parametresinden ise iki elamanlı bir tuple bekliyoruz. Bu parametrelere verilecek değerler çizilecek olan karemizin rengini ve konumunu belirleyecek.

Şimdi de yeni Kare sınıfımızı nasıl kullanabileceğimize bakalım:

import pygame, sys
from kare import Kare
pygame.init()

pencere = pygame.display.set_mode((500,400))

renkler_konumlar = [[(255,0,0),(50,50)],
                    [(0,255,0),(150,100)],
                    [(0,0,255),(75,150)]]

kareler = []

for renk, konum in renkler_konumlar:
    kareler.append(Kare(renk,konum))

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    pencere.fill((255,255,255))

    for kare in kareler:
        pencere.blit(kare.image, kare.rect)

    pygame.display.flip()

renkler_konumlar adında bir liste oluşturduk ve içine 3 liste daha oluşturduk. Bu üç listeye de Kare sınıfımıza gireceğimiz parametreleri girdik. Hemen altında kareler adında boş bir liste oluşturduk. Bu listeye for döngüsü yardımıyla, renkler_konumlar listesinden gelen verilerle oluşturulan Kare sınıflarımızı ekledik. Oyun döngümüzde ise yine bir for döngüsüyle kareler listesindeki Kare nesnelerini ana yüzeyimize çizdirdik. Sonuç olarak birbiriyle bitişik halde; kırmızı, yeşil ve mavi kareler çizdirmiş olduk.

Sprite sınıfının kullanımı bu kadarla bitmiyor; update() methoduyla Kare sınıfımızda yapılan değişiklikleri ekrana yansıtabiliriz. Bu sayede oyun döngümüzde kalabalık yapan onlarca satır kodu update() methodlarında yazabiliriz.

# kare.py
from pygame.sprite import Sprite

class Kare(Sprite):
    def __init__(self, renk, konum):
        Sprite.__init__(self)
        self.image = pygame.Surface((100,100))
        self.image.fill(renk)
        self.rect = self.image.get_rect()
        self.rect.x, self.rect.y = konum

    def update(self):
        if pygame.key.get_pressed()[pygame.K_LEFT]:
            self.rect.x -= 1
        if pygame.key.get_pressed()[pygame.K_RIGHT]:
            self.rect.x += 1
        if pygame.key.get_pressed()[pygame.K_UP]:
            self.rect.y -= 1
        if pygame.key.get_pressed()[pygame.K_DOWN]:
            self.rect.y += 1

update methodumuzda klavye ok tuşlarıyla karemizin yer değiştirmesini sağlıyoruz. Bu kodu Sprite kullanmadan önce oyun döngümüze yazıyorduk. Bu durumda oyun döngümüze update() methodumuzu yazmamız yeterli olacaktır:

import pygame, sys
from kare import Kare
pygame.init()

pencere = pygame.display.set_mode((500,400))

kare = Kare((255,0,0),(50,50))

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    pencere.fill((255,255,255))

    kare.update()

    pencere.blit(kare.image, kare.rect)
    pygame.display.flip()

Bu kadar basit… Sekiz satırlık kodu update() methodumuza yazdık ve oyun döngümüzde çağırarak tek satır yer kaplamasını sağladık.

Spritelar genellikle animasyon için kullanılır. Sprite animasyon dediğimiz bu terim, ard arda oynatılan resimlerle meydana gelen hareketli yüzeyleri belirtir. İnternette “Sprite sheet” diye aratırsanız 2B oyunlarda kullanılmak üzere çizilmiş yüzlerce; kare kare çizilip, tek yerde toplanmış resim dosyaları bulacaksınız. Bu resimleri kullanarak örneğin; oyunumuzdaki karakterin hareketlerini oluşturabilir ve klavye kontrolleriyle animasyonları gösterebiliriz. Tabii bunu tek resim dosyasından, grafiklerin tek tek dikdörtgen alanını bulup kullanacağınız gibi her kareyi tek bir resim dosyası haline getiripte Sprite animasyonunu oluşturabilirsiniz.

Çok basit bir Sprite animasyonu yapalım ve gelecek derslere motive edici bir etkisi olmasını dileyelim.

# asker.py
from pygame.sprite import Sprite
import pygame

class Asker(Sprite):
    def __init__(self, konum):
        Sprite.__init__(self)
        self.resimler = [pygame.image.load("00.png"), pygame.image.load("01.png")]
        self.image = self.resimler[0]
        self.rect =  self.image.get_rect()
        self.rect.x, self.rect.y = konum
        self.say = 0

    def update(self):
        if pygame.key.get_pressed()[pygame.K_LEFT]:
            if self.say >= 2:
                self.say = 0
            self.rect.x -= 4
            self.image = self.resimler[self.say]
            self.say += 1

        if pygame.key.get_pressed()[pygame.K_RIGHT]:
            if self.say >= 2:
                self.say = 0
            self.rect.x += 4
            self.image = pygame.transform.flip(self.resimler[self.say],1,0)
            self.say += 1

self.resimler adında bir liste oluşturduk ve 00.png ve 01.png resimlerinin Surface halini listeye ekledik. Her Sprite nesnesinde olması gereken self.image niteliğine self.resimler listesinin ilk elemanını atadık. Bu resim karakterin durduğu anı temsil ediyor.

self.say adında da bir sayaç oluşturduk; bunun amacı da self.resimler listesindeki Surface nesnelerini sırayla göstermek içindir.

update() methodumuz da sağ ve sol yönler için sağ ve sol ok tuşlarına basılması durumu için iki adet if bloku açtık. Bu if bloklarında self.rect adındaki rect nesnemizin x niteliğinin değerlerini artırıp, azaltarak sağa ve sola hareketini sağladık. self.image niteliğini; self.say ın tuttuğu sayıyla, self.resimler listesinde o sıraya tekabul eden Surface nesnemizle değiştirdik ve ardından self.say ın değerini bir artırdık. Bu şekilde sağ ve sol ok tuşlarına basılınca self.resimler listesindeki Surface nesneleri akıcı şekilde ekrana çizilecektir. Sprite karelerinin az olması çok hızlı akmasına neden oluyor, ama siz elinizdeki sprite grafiklerinizle çoğaltıp test edebilirsiniz.

Sağ ok tuşuna basıldığında çalışacak kodlara baktığımızda daha önce görmediğimiz pygame.transform.flip() ile karşılaşıyoruz. transform modülünün flip fonksiyonu ile ilk parametresine verdiğimiz Surface nesnemizin ölçeğini x ve y konumunda değiştirebiliyoruz. İkinci parametre ile x ölçeğini, üçüncü parametre ile y ölçeğini değiştiriyoruz. Ben burda x ölçeğine 1 değerini vererek resmin sağ ok tuşuna basılınca x yönünde dönmesini sağladım ve askerimiz de sağa bakmış oldu.

import pygame, sys
from asker import Asker
pygame.init()

pencere = pygame.display.set_mode((500,400))

asker = Asker((250,50))

saat = pygame.time.Clock()
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    pencere.fill((255,255,255))

    asker.update()

    pencere.blit(asker.image, asker.rect)
    pygame.display.flip()
    saat.tick(24)

asker.py den Asker sınıfını import ettik ve konumunu 250×50 ye ayarladık. Bu sefer Clock nesnesi oluşturduk ve 24 fps olacak şekilde ayarladık. Zaten sprite resimlerin sayısı az olduğu için hızlı akıyordu; bu sayede biraz da olsa hem kısmış olduk, hemde hareket ediş hızını azalttık. Oyun döngümüzde update() methodunu yazdık bu sayede klavye ok tuşlarına bastığımızda kodlarımız çalışacaktır…

Kodların son halini buradan indirebilirsiniz.

Yazım hatası varsa bildiriniz.
Bu yazı Creative Commons-BY-SA ile lisanslanmıştır. Bu yazıyı ilk sahibini belirtmek ve aynı lisansla dağıtmak koşuluyla kullanabilirsiniz.

Benzer Yazılar:

  1. Pygame ile Oyun Programlama – Surface Modülü
  2. Pygame ile Oyun Programlama – Image Modülü
  3. Pygame ile Oyun Programlama – Draw Modülü
  4. Pygame ile Oyun Programlama – Time Modülü
  5. Pygame ile Oyun Programlama – Rect Modülü
3
Ağu

Frame Per Second. Yani sayide ekrana verilen kare sayısı…

Her oyun döngüden ibarettir; ekrana verilen görüntü kare kare çizilir ve döngü ile oyun akışı sağlanır. Önceki derslerde gördüğünüz üzere bir while döngüsüyle oyunumuzun döngüsünü sağlıyorduk. Burada while döngüsünün saniyede kaç kere işlediğini bilemiyoruz.

Oyun yapım firmaları her oyun için fps değeri belirler. Eğer işlemciniz yeterli güçte değilse oyun döngüsü yavaş olacağından beklenen fps yi sağlayamaz ve oyun kesik kesik veya yavaş görünür. Bu da oyunun oynanma olasılığını etkileyen bir durumdur. Ayrıca fps değerinin değişiklik göstermesi oyunun bazı yerlerinde akışın hızlı bazı yerlerinde daha yavaş olmasına yol açar. Bunun nedenlerinden biri de ekrana çizilen nesnelerin çokluğu ve azlığıdır.

Bu zamana kadar yaptığımız örneklerde lüzum olmadığı için fps ile ilgili bir işlem yapmadık. Ancak şöyle bir durumda kullanım ihtiyacı doğabilir.

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((500,400))

kare = pygame.Surface((100,100))
kare.fill((255,0,0))
kare_rect = pygame.Rect((0,0), kare.get_size())

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    if pygame.key.get_pressed()[pygame.K_UP]:
        kare_rect.y -= 2
    if pygame.key.get_pressed()[pygame.K_DOWN]:
        kare_rect.y += 2
    if pygame.key.get_pressed()[pygame.K_LEFT]:
        kare_rect.x -= 2
    if pygame.key.get_pressed()[pygame.K_RIGHT]:
        kare_rect.x += 2

    pencere.fill((0,0,0))

    pencere.blit(kare, kare_rect)
    pygame.display.flip()

Bu örnekte şu kısma odaklanmanızı istiyorum:

    if pygame.key.get_pressed()[pygame.K_UP]:
        kare_rect.y -= 2
    if pygame.key.get_pressed()[pygame.K_DOWN]:
        kare_rect.y += 2
    if pygame.key.get_pressed()[pygame.K_LEFT]:
        kare_rect.x -= 2
    if pygame.key.get_pressed()[pygame.K_RIGHT]:
        kare_rect.x += 2

Burada olayları kullanmadan pygame.key modülünün get_pressed() fonksiyonuyla hangi tuş(lar)a basıldığını liste olarak alıyoruz. K_UP, K_DOWN gibi değişkenler sayı tuttuğu için bu listeden o sayıya denk gelen liste elemanının 1 mi 0 mı olduğuna bakıp işlem yapıyoruz. Bu satırlarda kırmızı bir kare yi bastığınız tuşlara göre ikişer pixel yer değiştirtiyoruz.

Örnek kodu test ettiğinizde ne kadar hızlı yer değiştirdiğini görmüş olmalısınız. Bizim amacımız burada kareyi hareket ettirmek, ama bu kadar hızlı bir şekilde yer değiştirmesini istemiyor olabiliriz. pygame.time modülünün sağladıklarıyla bunu kontrol altına alabiliriz.

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((500,400))

kare = pygame.Surface((100,100))
kare.fill((255,0,0))
kare_rect = pygame.Rect((0,0), kare.get_size())

saat = pygame.time.Clock()
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    if pygame.key.get_pressed()[pygame.K_UP]:
        kare_rect.y -= 2
    if pygame.key.get_pressed()[pygame.K_DOWN]:
        kare_rect.y += 2
    if pygame.key.get_pressed()[pygame.K_LEFT]:
        kare_rect.x -= 2
    if pygame.key.get_pressed()[pygame.K_RIGHT]:
        kare_rect.x += 2

    pencere.fill((0,0,0))

    pencere.blit(kare, kare_rect)
    pygame.display.flip()
    saat.tick(30)

saat adında bir Clock nesnesi tanımladık. Bu nesne yardımıyla oyun döngümüzün saniyedeki kaç kere dönmesi gerektiğini söyleyeceğiz.

Oyun döngümüzün sonunda Clock nesnemizin tick methoduyla saniyede kaç kere döngü oluşması gerektiğini belirtiyoruz. 30 parametresiyle while döngüsü saniyede otuz kere dönecektir. Bu sayede karemizi daha düzgün bir şekilde hareket ettirebileceğiz.

Peki, biz oyun döngümüzün saniyede otuz kere döndüğünü nasıl anlayacağız?

pygame.display.set_caption("%d"%saat.get_fps())

get_fps() methoduyla float olarak saniyedeki kare sayısını öğreniyoruz ve yukarıda ki kod parçasını oyun döngümüze ekleyerek pygame penceremizin başlığını fps değeri olarak değiştiriyoruz. Tabii bu değer hiç bir zaman sabit olmayacaktır. Çünkü bilgisayarınızdaki her hangi bir işlem, ya da oyunda ki bir olay sonucu fps değeri ufakta olsa değişecektir.

Pygame ile yaptığınız bir oyuna bu kadar basit bir şekilde fps değeri verebilirsiniz.

Pygame kodunuzu çalıştırdığınızda pygame.init() in bulunduğu satır işlendiğinde siz uygulamayı sonlandırana kadar sürecek bir zaman akışı olacaktır. Kod çalışırken işlediğiniz her pygame.time.get_ticks() fonksiyonu o anda pygame.init() işlendikten beri kaç saniye geçtiğini milisaniye olarak döndürür. Eğer bu fonksiyonu oyun döngünüzde print ederseniz çıktı olarak sürekli geçen saniyeyi milisaniye olarak gösterir.

pygame.time.set_timer(pygame.QUIT, 10000)

set_timer() ile olay tipini ve tetiklenecek süreyi milisaniye olarak girerek bir zamanlayıcı oluşturabiliriz. Yukarıda ki kodda on saniye de bir QUIT tipinde olay kuyruğa eklenecektir. Bu olayı yakaladığınız kod varsa her on saniyede bu kod işlenecektir.

Sadece QUIT değil KEYDOWN, MOUSEBUTTONDOWN, USEREVENT gibi olay tiplerinide kullanabilirsiniz. Peki bu set_timer() ile ne yapabiliriz? Yazdığınız bir oyunun demosunu yayınlamaya karar verdiniz ve belirtilen süre kadar oynanabilsin istiyorsunuz. Basitçe yukarıdaki kodu kullanarak ve oynanma süresini ayarlıyarak kullanabilirsiniz.

1000*60*60 gibi bir parametre girerek bir saatlik oynama süresi koyabilirsiniz. Tabii ki olay kontrolünde ise şu kod olmalı:

if event.type == pygame.QUIT:
    sys.exit()

Bu fonksiyon ile hayal gücünüz ile sınırlı kodlar yazabilirsiniz. İleriki derslerde lazım olursa daha iyi kavrayacağınızdan emin olun.

Yazım hatası varsa bildiriniz.
Bu yazı Creative Commons-BY-SA ile lisanslanmıştır. Bu yazıyı ilk sahibini belirtmek ve aynı lisansla dağıtmak koşuluyla kullanabilirsiniz.

Benzer Yazılar:

  1. Pygame ile Oyun Programlama – Image Modülü
  2. Pygame ile Oyun Programlama – Music Modülü
  3. Pygame ile Oyun Programlama – Surface Modülü
  4. Pygame ile Oyun Programlama – Display Modülü
  5. Pygame ile Oyun Programlama – Mixer Modülü
2
Ağu

Bir önceki derste pygame.mixer modülü altında bulunan music modülünü öğrendik. music modülü ile oyun içi müzik oynatmamızı sağlayacak bilgiler edindik. Özellikle dedik ki, music modülü ile efektleri istediğimiz gibi oynatamayız, bunun için mixer modülünün sağladığı özellikleri kullanmalıyız…

mixer modülünde bu efektlerle çalışmak için iki adet sınıfımız var. Bunları ve diğer fonksiyonları öğrenmek için basit bir oyun yapalım…

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,200))

ses = pygame.mixer.Sound("shotgun3.wav")
ses.play()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    pencere.fill((0,0,0))

    pygame.display.flip()

Örneğimizde ses adındaki değişkene Sound nesnesi atadık ve bu ses nesnesi shotgun3.wav dosyasını barındırsın dedik. Hemen ardından Sound sınıfının play() methoduyla ses dosyasını oynattık. Örneği çalıştırdığınızda silah sesi bir defa duyulacaktır.

play() methodu ile ses dosyasını oynatmakla beraber bu method bir Channel nesnesi döndürür. Channel nesnesi oynatılacak ses için bir kanal oluşturur. pygame de en fazla 9 kanal oluşturabilirsiniz bu kanallar 0-8 arası sıralanır. music modülünde ki play() fonksiyonu gibi bu methodda ilk parametresine gireceğiniz rakama göre kaç kez oynatılacağına karar verebilirsiniz.

Oynatılan ses dosyası uzunsa ve durdurmak isterseniz stop() methodu ile bu işi halledebilirsiniz. music modülünde anlattığım set_volume() ve get_volume() fonksiyonları da Sound sınıfında aynı şekilde çalışmaktadır. music modülünde olmayan şey ise get_length() methodudur. Bu method ile ses dosyanızın uzunluğunu öğrenebilirsiniz.

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,200))

ses = pygame.mixer.Sound("shotgun3.wav")
ses.play()
print ses.get_length()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    pencere.fill((0,0,0))

    pygame.display.flip()

Benim oynattığım ses dosyası 2.24653061224 saniyeydi.

Sound sınıfında değinmek istediğim son method ise get_num_channels() methodu. Bu method bağlı olduğu Sound nesnesinin kaç kanalı kullandığını sayı olarak döndürür. Normal olarak yukarıdaki örneğe print ile bu methodun döndürdüğü değeri yazdırırsak 1 sonucunu alırız. Ses oynatıldıktan sonra işletilen her play() methodu bu methodun çıktısını sabit kılacaktır. Eğer siz bir ses dosyasının oynatılması bitmeden üç kere daha play() methodunu çalıştırırsanız aynı sesten dört kez oynatılacaktır ve bu koddan sonra print ile get_num_channels() methodunun döndürdüğü değeri yazdırırsanız 4 rakamını çıktıda görürsünüz.

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,200))

ses = pygame.mixer.Sound("shotgun3.wav")
ses.play()
ses.play()
ses.play()
ses.play()
print ses.get_num_channels()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    pencere.fill((0,0,0))

    pygame.display.flip()

Dört adet kanal kullanılacak ve sesler örneğe göre aynı anda oynatılacaktır. Bu yüzden tek bir ses oynatılmış gibi gelecek, ama ses seviyesi artmış sanacaksınız.

Yukarıda dediğim gibi en fazla dokuz kanal kullanılabiliyor. Eğer dokuz kanaldan fazlasını kullanmaya kalkarsanız fazla sesler oynatılmayacaktır.

play() methodunun Channel nesnesi döndürdüğünü söylemiştik. İstersek Channel nesnelerini kendimizde tanımlayabiliriz.

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,200))

ses = pygame.mixer.Sound("shotgun3.wav")
kanal = pygame.mixer.Channel(0)
kanal.play(ses)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    pencere.fill((0,0,0))

    pygame.display.flip()

Örnekte Sound nesnesini muhafaza ettik ve kanal adında bir Channel nesnesi oluşturduk. Bu kanalın id sini 0 olarak belirttik ve Channel nesnesinin play() methoduna Sound nesnesini parametre olarak verdik. Kodu çalıştırdığımızda bir kez shotgun3.wav ses dosyası oynatılacaktır. Her kanal tek ses dosyası oynatabildiği için birden fazla oynatmalarda önceki sesler kesilecektir.

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,200))

ses = pygame.mixer.Sound("shotgun3.wav")
kanal = pygame.mixer.Channel(0)
kanal.play(ses)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                kanal.play(ses)

    pencere.fill((0,0,0))

    pygame.display.flip()

Bu kodu çalıştırıp boşluk tuşuna sürekli bastığınızda önceki seslerin kesildiğini en son bastığınızdaki sesin çaldığını göreceksiniz.

Channel sınıfının music modülünde de olan; stop(), set_volume(), get_volume(), pause(), unpause() methodları mevcuttur. Tekrar anlatmama lüzum görmüyorum. Çünkü aynı şekilde çalışıyorlar. Yalnız set_volume() methoduna isterseniz iki ayrı ses değeri vererek sağ ve sol hoparlörün ayrı ayrı ses seviyesinde olmasını sağlayabilirsiniz.

Şimdi öğrendiklerimizle basit bir hedef vurma oyunu yapmaya başlayalım. Nişangah ve hedef resimlerini seçelim. Malesef bu oyunda en büyük musluk tamircisi Mario karakterini vuracağız :)

Yapacağımız oyun da ekranda rasgele belirecek bir hedef olacak ve onu vurduğumuzda hedef rasgele bir yerde tekrar belirecek. Her ateş ettiğimizde silah sesi suyacağız ve ard arda ateş ettiğimizde önceki seslerde duyulacak. Hedefi ise nişangah resmini fare imleciyle paralel hareket ettireceğiz ve imleci görünmez yapacağız. Yani nişangahın merkez noktası aslında fare imlecinin olduğu yer olacak. Bizde fare imleci konumuyla hedefin çarpışma kontrolünü yapıp çarpışma varsa ateş ettiğimizde vurmuş olacağız. 20 kere başarılı atıştan sonra oyunumuz bitecek.

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((640,480))

nisan = pygame.image.load("nisan.png")
nisan_rect = pygame.Rect((0, 0), nisan.get_size())

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    pencere.fill((0,0,0))

    nisan_rect.center = pygame.mouse.get_pos()
    pencere.blit(nisan, nisan_rect)
    pygame.display.flip()

Öncelikle 640×480 boyutlarında pencere oluşturduk. nişan.png resmimizi yükledik ve Rect nesnesini oluşturduk. Ana döngümüzde nisan_rect adındaki Rect nesnemizin center-merkez koordinatını pygame.mouse.get_pos() ile fare imlecinin koordinatı olarak ayarladık. pencere.blit() ile de güncellenen Rect nesnemizin içeriğine göre ekrana fare imlecinin hareketiyle hareket eden bir nişangah çizdirdik. Uygulamayı çalıştırdığımızda fare imlecinin nişangahın merkezinde olduğu görürüz. Daha güzel olması için o fare imlecini görünmez yapalım ve fare sol tuşuyla her basışımızda ateş sesi gelsin.

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((640,480))

ses = pygame.mixer.Sound("shotgun3.wav")

nisan = pygame.image.load("nisan.png")
nisan_rect = pygame.Rect((0, 0), nisan.get_size())

pygame.mouse.set_visible(False)
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                ses.play()

    pencere.fill((0,0,0))

    nisan_rect.center = pygame.mouse.get_pos()
    pencere.blit(nisan, nisan_rect)
    pygame.display.flip()

Sound nesnemizi oluşturduk ve shotgun3.wav ses dosyasını kullanmasını söyledik. Fare imlecini görünmez yapmak için pygame.mouse.set_visible() fonksiyonuna False parametresini girdik. Olay kontrolüne MOUSEBUTTONDOWN ile fare tuşuna basıldığı an dedik; event.button == 1 ile de sol tuşa basılmışsa ses dosyamızı oynatmasını söyledik. Kodu çalıştırdığımızda her sol fare tıklamasında ateş etme sesi gelecektir.

Şimdi ise hedefimizi ekrana rasgele çizdirelim ve çarpışma algılaması ile ateş etme durumunda hedefi başka yere taşıyalım. Ekranın üst-orta kısmına ise kaç kez vurduğumuzu yazdıralım. 20 kez vurduğumuzda oyun bitiş ekranı karşılaşın.

import pygame, sys, random

pygame.init()

pencere = pygame.display.set_mode((640,480))

ses = pygame.mixer.Sound("shotgun3.wav")

nisan = pygame.image.load("nisan.png")
nisan_rect = pygame.Rect((0, 0), nisan.get_size())

hedef = pygame.image.load("mario.png")
hedef_rect = pygame.Rect((0, 0), hedef.get_size())

font = pygame.font.Font("GentiumPlus.ttf",50)

pygame.mouse.set_visible(False)
hedefte_mi = False
sayac = 0
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                if hedefte_mi:
                    sayac += 1
                    hedef_rect.x, hedef_rect.y = random.randrange(600), random.randrange(400)
                ses.play()

    if sayac < 20:
        sayac_yaz = font.render("%.2d"%sayac,True,(255,255,0))
        if hedef_rect.collidepoint(pygame.mouse.get_pos()):
            hedefte_mi = True
        else:
            hedefte_mi = False

        pencere.fill((0,0,0))

        nisan_rect.center = pygame.mouse.get_pos()
        pencere.blit(hedef, hedef_rect)
        pencere.blit(sayac_yaz, (300,0))
        pencere.blit(nisan, nisan_rect)
    else:
        pencere.fill((0,0,0))
        oyun_bitti = font.render(u"OYUN BİTTİ. KAZANDINIZ!",True,(0,255,0))
        pencere.blit(oyun_bitti, (50,200))

    pygame.display.flip()

hedef ismiyle mario.png yi tanımladık. hedef_rect ile ilk rect değerini girdik. font değişkenine de Font nesnemizi tanımladık. Kaç kez vurduğumuzu hesaplamak için sayac adlı değişkeni, fare pozisyonu ile hedef çarpışıyor mu diye hedefte_mi değişkenini tanımladık. Olay kontolümüzde fare sol tuşuna bastığımızda hedefte_mi değişkeninin değerini kontrol ediyoruz. Eğer True ise sayacımız +1 yükseliyor. ve hedef_rect in x ve y koordinatlarını rasgele bir değere atıyoruz. Yani hedef vurulduğu zaman sayaç yükselecek ve hedef konum değiştirecektir. Oyun döngümüzde ise bir if bloku açtık. Oyunumuz sayaç 20 değerini alınca biteceği için sayac değişkeninin değeri 20 den küçük olduğu sürece alttaki işlemleri yapsın dedik.

if blokunda sayac_yaz değişkenine sayac değişkenin değerini kullanarak sarı renkli olacak şekilde Surface nesnesi oluşturduk. Her döngüde bu Surface nesnesi yeniden oluşacağı için sayac değişkenindeki değişiklikleri de güncellemiş oluyoruz. Hemen altına hedef ile fare imlecinin pozisyonunun çarpışma kontrolünü yaptık ve çarpışma varsa hedefte_mi değişkeninin değerini True yaptık. Aksi durumlarda False olsun dedik. ana if blokunun geriye kalan kısmında ise değişikliklere göre nişangahı ve hedefi sürekli çizdiren kodları yazdık. Sayacımızı ise yukaro-orta kısma yazdırdık.

else blokunda ise sayac değişkeninin değeri 19 dan yüksek olduğunda ise ekranı temizledik ve ortasına OYUN BİTTİ. KAZANDINIZ! yazısını yazdırdık. Bu halde sol fare tıklamasıyla ateş etme sesini hala oynatabilirsiniz. if blokundan çıktık ve ekranı güncelleyen flip() fonkyonumuzu yazdık.

Uygulamanın son halini buradan indirebilirsiniz.

Yazım hatası varsa bildiriniz.
Bu yazı Creative Commons-BY-SA ile lisanslanmıştır. Bu yazıyı ilk sahibini belirtmek ve aynı lisansla dağıtmak koşuluyla kullanabilirsiniz.

Benzer Yazılar:

  1. Pygame ile Oyun Programlama – Music Modülü
  2. Pygame ile Oyun Programlama – Image Modülü
  3. Pygame ile Oyun Programlama – Display Modülü
  4. Pygame ile Oyun Programlama – Surface Modülü
  5. Pygame ile Oyun Programlama – Font Modülü
28
Tem

Oyunların vazgeçilmezlerinden biri de ses efektleri ve oyun içi müziktir. Oyuna kendinizi kaptırmanızda arka planda çalan müzik, düşmana savurduğunuz kılıcın çarpma sesi büyük bir etkendir. Pygame de bize oyunumuzda efekt ve/veya müzik çaldırmamız için modüller sunar. Bu derste mixer modülünde bulunan music modülünü öğreneceğiz ve küçük ve kolay bir müzik çalar yapacağız.

Öncelikle kendinize bir mp3 ya da ogg müzik dosyası bulunuz. Ben TheStronges.mp3 adlı müzik dosyası ile çalışacağım. İlk örneğimizde bu dosyayı basit olarak oynatacağız…

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,200))

muzik_adi = "TheStronges.mp3"

pygame.mixer.music.load(muzik_adi)
pygame.mixer.music.play()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    pencere.fill((0,0,0))

    pygame.display.flip()

300×200 boyutlarında boş ve siyah bir ekran karşımıza çıkacak. music modülünün load() methodu müzik dosyasını yükleyecek. play() methodu ise müziği oynatacaktır. Bu method isteğe bağlı olarak iki adet parametre alır. İlk parametresine gireceğiniz pozitif bir sayıyla kaç kere çalması gerektiğini belirtebilirsiniz. İkinci parametresi ise müziğin kaçıncı saniyesinden başlatacağınızı float yani kayan noktalı bir değer girebilirsiniz. Ör: 10.5 değeri girerseniz 10.5 saniyeden itibaren oynatılır.

Şimdi ise uygulamamızı geliştirelim. Klavye tuşlarıyla müzik dosyasını oynatmayı, durdurmayı, bekletmeyi vs. kontrol edelim.

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,200))

muzik_adi = "TheStronges.mp3"
pygame.mixer.music.load(muzik_adi)

pause = False
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_f:
                pygame.mixer.music.play()
            if event.key == pygame.K_s:
                pygame.mixer.music.stop()
            if event.key == pygame.K_p:
                if pause:
                    pygame.mixer.music.unpause()
                    pause = False
                else:
                    pygame.mixer.music.pause()
                    pause = True
            if event.key == pygame.K_r:
                pygame.mixer.music.rewind()

    pencere.fill((0,0,0))

    pygame.display.flip()

Mükemmel olmasa da öğrenmek için ideal bir örne kolduğunu düşünüyorum. Örneğimizi çalıştırdığımızda karşımıza boş ve siyah bir ekran gelecek. Klavyeden F tuşuna bastığımızda play() methodu müziği oynatacak, S tuşuna basınca stop() methodu müziği durduracaktır. stop() ile durdurulan müzik dosyası durdurulduğu saniyede kalmaz ve başa döner. P tuşuna bastığımızda ise False değerini verdiğimiz pause değişkeni yardımıyla duruma göre müziği bekletmeye ya da kaldığı yerden oynatılacaktır. R tuşuyla da rewind() methodu çalışacak ve çalan müziği başa sarıp oynatacaktır.

Uygulamamız dediğim gibi mükemmel değil. Özellikle müziği oynatmadan P tuşuna basarsak pause değişkeninin değeri değişeceğinden hata vermese de hatalı olacaktır. Müziği oynatmadan bir kere P tuşuna basın sonra oynatın ve tekrar P tuşuna basarak ne demek istediğimi anlayacaksınız. music modülünün get_busy() methodu müzik dosyası oynatıldıktan çalıp bitene kadar True değeri döndürür. Bu method yardımıyla bekletme işini yapan kodumuzu iyileştirebiliriz.

                if pause:
                    pygame.mixer.music.unpause()
                    pause = False
                else:
                    pygame.mixer.music.pause()
                    pause = True

Bu koda tek bir satır ekleyerek sorunu giderebiliriz.

                if pygame.mixer.music.get_busy():
                    if pause:
                        pygame.mixer.music.unpause()
                        pause = False
                    else:
                        pygame.mixer.music.pause()
                        pause = True

Uygulamamızı biraz daha geliştirelim ve ses seviyesini değiştirme özelliği kazandıralım. Ayrıca çalan müziğin kaçıncı saniyede olduğunu, dosya adını ve ses seviyesini pygame penceresinde gösterelim.

#-*- coding:utf-8 -*-
import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,200))

muzik_adi = "TheStronges.mp3"
pygame.mixer.music.load(muzik_adi)
pygame.mixer.music.play()

font = pygame.font.Font("GentiumPlus.ttf", 16)

muzik_adi_yazdir = font.render(muzik_adi, True, (255,255,0))

pause = False
ses_seviyesi = 1.0
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_f:
                pygame.mixer.music.play()
            if event.key == pygame.K_s:
                pygame.mixer.music.stop()
            if event.key == pygame.K_p:
                if pygame.mixer.music.get_busy():
                    if pause:
                        pygame.mixer.music.unpause()
                        pause = False
                    else:
                        pygame.mixer.music.pause()
                        pause = True
            if event.key == pygame.K_r:
                pygame.mixer.music.rewind()
            if event.key == pygame.K_UP:
                if not pygame.mixer.music.get_volume() >= 1.0:
                    ses_seviyesi += 0.1
                    pygame.mixer.music.set_volume(ses_seviyesi)
            if event.key == pygame.K_DOWN:
                if not pygame.mixer.music.get_volume() < = 0:
                    ses_seviyesi -= 0.1
                    pygame.mixer.music.set_volume(ses_seviyesi)

    pencere.fill((0,0,0))
    saniye_kac = font.render(u"Şuan müzik %d. saniyede."%int(pygame.mixer.music.get_pos()/1000), True, (0,255,0))
    ses_seviyesi_kac = font.render(u"Ses seviyesi: %d"%int(pygame.mixer.music.get_volume()*100), True, (0,255,0))

    pencere.blit(muzik_adi_yazdir, (80,50))
    pencere.blit(saniye_kac, (80,75))
    pencere.blit(ses_seviyesi_kac, (80,100))
    pygame.display.flip()

Bu örneğimizde font adında bir Font nesnesi oluşturduk. Statik olarak duracağı için hemen altında müzik dosyasının ismini içeren bir Surface nesnesi oluşturduk ve döngümüzde bunu 80x50 konumuza çizdirdik.

ses_seviyesi adında bir değişken tanımladık ve float olarak 1.0 değerini girdik. Bu değişkeni ses seviyesini değiştirmek istediğimizde değerini değiştirecez ve yeni ses seviyesi olarak kullanacağız.

Olay kontrolu kısmına yukarı ok tuşuyla, aşağı ok tuşunun kontrolünü ekledik ve bunların ses seviyesini değiştirmesini sağladık. Tuşlara bastığımızda duruma göre ses seviyesini 0.1 artırıp azaltıyoruz ve set_volume() methodu ile ses seviyesini belirliyoruz. if bloklarıyla da ses seviyesini 0-1 arasında tutuyoruz.

Dinamik olarak değişkenlik gösterecek olan ses seviyesi ve müziğin o andaki saniyesinin oyun döngümüz arasında Surface nesnelerini oluşturduk ve alt alta gelecek şekilde ekrana çizdirdik.

Kodu çalıştırdığımızda müzik oynamaya başlayacak ve saniyeyi gösteren Surface nesnesi sürekli güncellenecek ve kaçıncı saniyede olduğunu gösterecektir. Yukarı-aşağı ok tuşlarıyla da ses seviyesi değişecek ve 0-100 arası değişiklikleri gösterecektir.

get_pos() ve get_volume() methodları float değer döndürdükleri için int() ile bu değerleri integer yaptık ve hata vermesini önledik. Ayrıca görünümleri güzel olsun diye ses seviyesini 100 ile çarpıp müzik çalarlardaki gibi ses seviyesi göstermiş olduk. get_pos() ise milisaniye döndürdüğü için saniyeye çevirmek için dönen değeri 1000 e bölmüş olduk.

Ekrana yazdırdığımız yazılarda Türkçe karakter olduğundan bunların gösterilmesi için tırnak işaretinden önce "u" harfini koyduk. Bu yazının unicode olduğunu söyler. Ancak kodumuzda Türkçe karakter olduğundan bu kodu çalıştırdığımızda hata alırız. Bunu önlemek içinde ilk satıra "#-*- coding:utf-8 -*-" ifadesini ekledik.

Denemeler yaparken fark ettimki, S tuşuna basıp stop() methodunu çalıştırdığımda saniyenin ilerlemeye devam ediyor. Bunu da bilgi olarak not düşelim...

music modülüyle bir müzik dosyasının oynatılmasını, durdurulmasını vs. öğrendik. Bu modülle oyunun arka planında müzik oynatabilirsiniz. Kılıç, bomba gibi efektleri de bu modülle oynatabilirsiniz, ama müzik oynarken load() methoduyla yükleme yapınca müzik durur. Efektleri music modülüyle değilde mixer modülüyle verebiliriz. İleriki derslerde mixer modülünüde öğreneceğiz.

Yazım hatası varsa bildiriniz.
Bu yazı Creative Commons-BY-SA ile lisanslanmıştır. Bu yazıyı ilk sahibini belirtmek ve aynı lisansla dağıtmak koşuluyla kullanabilirsiniz.

Benzer Yazılar:

  1. Pygame ile Oyun Programlama – Image Modülü
  2. Pygame ile Oyun Programlama – Font Modülü
  3. Pygame ile Oyun Programlama – Display Modülü
  4. Pygame ile Oyun Programlama – Draw Modülü
  5. Pygame ile Oyun Programlama – Surface Modülü
26
Tem

Her Surface nesnesi boyutuyla ve çizildiği konumla bir dikdörtgen alanı kaplar. Bu dikdörtgen alanlar Rect() modülüyle ifade edilir. Rect ile Surface modülünü anlatırken karşılaşmıştık. Surface modülünün get_rect() methoduyla bir Rect nesnesi döndürmüştük. İşte bu rect bilgisi ile ekrana çizdirdiğimiz Surfacelerin hareketlerini yönetebiliriz.

Rect modülünün bir çok methodu vardır. Yalnız hiç kullanmadığımdan ve bilmediğimden sadece bir kısmını göreceğiz ve zaten anlatacağım kısımda en çok kullanılan methodlardır. Bu yazıyı okuyup bitirdiğinizde ekranda bir Surface i nasıl hareket ettireceğimizi ve çarpışma kontrolünü öğrenmiş olacaksınız.

Şimdi ekrana iki adet Surface çizdirelim ve Rect modülünü öğrenmeye başlayalım…

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((500,500))

yesil_kare = pygame.Surface((100,100))
yesil_kare.fill((0,255,0))
yesil_kare_rect = pygame.Rect((100,100), yesil_kare.get_size())

mavi_kare = pygame.Surface((100,100))
mavi_kare.fill((0,0,255))
mavi_kare_rect = yesil_kare_rect.copy()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_w:
                yesil_kare_rect = yesil_kare_rect.move(0,-5)
            if event.key == pygame.K_s:
                yesil_kare_rect = yesil_kare_rect.move(0,5)
            if event.key == pygame.K_a:
                yesil_kare_rect = yesil_kare_rect.move(-5,0)
            if event.key == pygame.K_d:
                yesil_kare_rect = yesil_kare_rect.move(5,0)

    pencere.fill((0,0,0))

    pencere.blit(yesil_kare, yesil_kare_rect)
    pencere.blit(mavi_kare, mavi_kare_rect)
    pygame.display.flip()

yesil_kare adında ve mavi_kare adında iki tane Surface nesnesi oluşturduk. Boyutlarını 100×100 pixel olarak atadık. fill() methodlarıyla da sırasıyla Surface leri yeşil ve maviye boyadık. yesil_kare_rect değişkenine pygame.Rect modülüyle dikdörtgen bir alan meydana getirdik. Bu dikdörtgen alan 100×100 konumunu ve yesil_kare Surface inin boyutunu içeriyor. mavi_kare_rect değişkenine ise Rect modülünün copy() methodunu kullanarak yesil_kare_rect in kopyasını atıyoruz.

Oyun döngümüzde olayları for döngüsüyle sıralıyoruz ve if bloklarıyla w, a, s, d tuşlarını yakalıyoruz. Bu tuşlara basıldığı an işlem yapılması için KEYDOWN tipinde olayları yakalayan bir kod yazdık. Bu if kontrolünde ise Rect modülünün move() methoduyla karşılaşıyoruz. move() methodu aldığı parametrelerle x ve y konumlarının değerini değiştirmemizi sağlıyor. Ancak, bu işlem tanımladığımız nesneye etki etmediğinden biz move() methoduyla dönen rect nesnesini tekrar ana nesnemize atıyoruz.

Bu olay kontrolünde W tuşuna bastığımızda rect nesnesinin y niteliği -5 artacaktır. Yani y değeri 100 ise yeni değeri 95 olacaktır. S tuşuna basıldığında ise y niteliği +5 artacaktır. y niteliğinin değeri 100 ise yeni değeri 105 olacaktır. A tuşuna basıldığında bu sefer x niteliği -5 artacak ve x in değeri 100 ise 95 olacaktır. D tuşuna bastığımızda ise x niteliğinin değeri +5 artacak ve önceki değeri 100 ise 105 olacaktır.

Olay kontrolünden sonra yesil_kare ve mavi_kare surfacelerini pencere.blit() ile ekrana çizdiriyoruz. Konumlarını girdiğimiz parametreye ise bu nesnelerin rect nesnelerini giriyoruz. Bu şekilde yesil_kare_rect ile mavi_kare_rect in değerleri değişirse ekrana yeni değerine göre çizim yapılacaktır. Bu kodu çalıştırdığımızda W, A, S, D tuşlarına basarak yeşil renkteki Surface i oynatabiliriz. Yalnız yesil_kare_rect in kopyasını mavi_kare_rect değişkenine atadığımızdan ve mavi_kare değişkenini yesil_kare den sonra yazdığımızdan dolayı yeşil renkli Surface ilk başta görünmeyecektir. Klavye tuşlarına basıp move() methoduyla taşıma yaptığınız zaman görünecektir.

Döngüde kullandığımız pencere.fill((0,0,0)) kodunu kullanmadan nasıl sonuç aldığınızı gözlemleyiniz.

Buraya kadar Rect modülünün copy() ile move() methodunu öğrendik. Bundan sonra oyunlarda vazgeçilmez olan nesnelerin çarpışma kontrolünü yapmamızı sağlayacak methodları öğrenmeye başlayabiliriz.

Nesnelerin çarpışması, bir nesnenin diğer nesneye temas etmesiyle oluşur. Bir nesnenin diğer nesneye temas edip etmediğini colliderect() methoduyla öğreniriz. İlk örneğimizden ilerleyerek hareket ettirdiğimiz yeşil kutumuzu mavi kutuya temas ettirdiğimizde mavi kutuyu rasgele bir alana kaçırtalım.

import pygame, sys, random

pygame.init()

pencere = pygame.display.set_mode((500,500))

yesil_kare = pygame.Surface((100,100))
yesil_kare.fill((0,255,0))
yesil_kare_rect = pygame.Rect((100,100), yesil_kare.get_size())

mavi_kare = pygame.Surface((100,100))
mavi_kare.fill((0,0,255))
mavi_kare_rect = yesil_kare_rect.copy()

pygame.key.set_repeat(100,10)
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_w:
                yesil_kare_rect = yesil_kare_rect.move(0,-2)
            if event.key == pygame.K_s:
                yesil_kare_rect = yesil_kare_rect.move(0,2)
            if event.key == pygame.K_a:
                yesil_kare_rect = yesil_kare_rect.move(-2,0)
            if event.key == pygame.K_d:
                yesil_kare_rect = yesil_kare_rect.move(2,0)

    if mavi_kare_rect.colliderect(yesil_kare_rect):
        mavi_kare_rect.x, mavi_kare_rect.y = (random.randrange(400), random.randrange(400))

    pencere.fill((0,0,0))

    pencere.blit(yesil_kare, yesil_kare_rect)
    pencere.blit(mavi_kare, mavi_kare_rect)
    pygame.display.flip()

Bir önceki kodumuza 3 satır kod ekleyerek çarpışma olması durumunda mavi renkli karenin konumunu değiştirmesini sağladık. while döngüsünden hemen önce kullandığımız pygame.key.set_repeat() fonksiyonu ile klavye tuşuna basılı tuttukça girdiğimiz parametrelere göre saniye de kaç kere tetikleneceğini belirttik. İlk örneği incelediyseniz basılı tutsanızda sadece bir kere yeşil karenin oynadığını görmüşsünüzdür. Bu fonksiyon bizi bundan kurtarıyor. Lakin W ve A tuşlarına basmak gibi çapraz hareket ettiremiyoruz. Çünkü KEYDOWN olayı bir defa da bir tuşa işlem yapıyor. Bir tuşa basılı tutarken diğerine tıklayınca daha iyi anlarsınız. Bu gibi bazı can sıkıcı durumlarda klavye kontrolünü pygame.key modülü ile çözmek gerekebilir.

Olay kontrolünden sonraki ana döngümüzün başına bir if bloku açtık ve mavi_kare_rect adlı Rect nesnemizin colliderect() methoduyla yesil_kare_rect adındaki Rect nesnesinin kontrolünü her döngüde kontrol edilmesini sağladık. Eğer bu iki nesne bir birine temas ediyorsa colliderect() methodu True döndüreceği için altındaki kod işlenecektir. Yani mavi_kare_rect in x ve y koordinatları 0-400 arası bir değere atanacak ve sonraki satırlarda ekrana yeni konumuyla çizilmesini sağlayacaktır. Bu satırda bize rasgele sayı üretme işini yapan random modülü kullandık. Bu modülün randrange() methodu girdiğimiz değeri aşmayacak şekilde rasgele sayı döndürür. Tabii sadece bu şekilde bir kullanımı yok, ama biz burada çarpışma olayını öğrendiğimiz için diğer kullanımları başka bahara kalıyor…

Dikdörtgen alanların çarpışma olayını colliderect() methoduyla kontrol ettik. Örnek kodumuzda iki nesnenin çarpışmasıyla mavi renkli karenin yerini oynattık. Peki, bunu fare imleciyle yapalım mı? collidepoint() methodu ise girdiğimiz konum bilgisine göre temas var mı onu bildirir. Büyük ihtimal bu method ile amaç fare imlecinin nesne ile temasının kontrolü için eklenmiş olmalı.

Şimdi yeşil renkli kutumuzdan geçici olarak kurtulup mavi kutuyu fare imleciyle temas olduğunda konumunu değiştirelim.

import pygame, sys,random

pygame.init()

pencere = pygame.display.set_mode((500,500))

mavi_kare = pygame.Surface((100,100))
mavi_kare.fill((0,0,255))
mavi_kare_rect = pygame.Rect((100,100), mavi_kare.get_size())

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    if mavi_kare_rect.collidepoint(pygame.mouse.get_pos()):
        mavi_kare_rect.x, mavi_kare_rect.y = (random.randrange(400), random.randrange(400))

    pencere.fill((0,0,0))

    pencere.blit(mavi_kare, mavi_kare_rect)
    pygame.display.flip()

Çok daha kısa bir kodla amacımıza ulaştık. Dikkat edeceğim nokta şurasıdır.

    if mavi_kare_rect.collidepoint(pygame.mouse.get_pos()):

Bura da mavi_kare_rect in collidepoint() methodunu kullandık ve parametre olarak pygame.mouse modülünün get_pos() fonksiyonunu kullandık. get_pos() fonksiyonu bize o an ki fare imlecinin konumunu verir. Bu kontrolü de döngü ile tekrarladığımız için fare imleci ekrandaki mavi renkli kutuya temas ettiği andan rasgele bir konumda belirecektir. Pygame in resmi dökümanlarını incelediğinizde fark edeceksinizki Rect modülünün başka methodlarıda var. Ben burada en çok kullanılan methodları anlatacağımı söylemiştim. O yüzden ileriki derslerde lazım olursa diğer methodlara da değinebilirim…

Yazım hatası varsa bildiriniz.
Bu yazı Creative Commons-BY-SA ile lisanslanmıştır. Bu yazıyı ilk sahibini belirtmek ve aynı lisansla dağıtmak koşuluyla kullanabilirsiniz.

Benzer Yazılar:

  1. Pygame ile Oyun Programlama – Surface Modülü
  2. Pygame ile Oyun Programlama – Image Modülü
  3. Pygame ile Oyun Programlama – Font Modülü
  4. Pygame ile Oyun Programlama – Draw Modülü
  5. Pygame ile Oyun Programlama – Display Modülü
23
Tem

Daha önceki derslerde anlatılmasa da örnek kodlarda Pygame in event modülünü kullandık. Event, Türkçe olay anlamına gelir. Pygame penceresinde; bastığımız her klavye tuşu, fare hareketi ve tıklamaları, pencere boyutlandırma(Pencere pygame.RESIZABLE bayrağıyla oluşturulmuşsa pencere boyutunu pencerenin kenarlarından değiştirebilirsiniz.) vs. bir olaydır ve bir Event() fonksiyonu oluşturur. pygame.event modülü bize bu olayları yönetmemiz için fonksiyonlar sunar.

Klavye ve/veya fare olaylarının birer Event() fonksiyonu oluşturduğunu söylemiştik. Bu fonksiyonların kullanıma göre nitelikleri vardır. Her oluşturulan Event() fonksiyonunun “type” adında bir niteliği mevcuttur. Bu nitelik olayın ne olduğunun bilgisini içerir. Bu type niteliği şu değerlerde olabilir:

QUIT – Pencerenin X butonuna basılmasıyla oluşur.
ACTIVEEVENT – Pencereye odaklandığında ya da odaktan çıkıldığında oluşur.
KEYDOWN – Klavyeden bir tuşa basıldığında oluşur.
KEYUP – Basılan tuş bırakıldığı zaman oluşur.
MOUSEMOTION – Fare imleci Pygame penceresinde hareket ettikçe oluşur.
MOUSEBUTTONUP – Fare tuşlarından basılı olan bırakıldığı zaman oluşur.
MOUSEBUTTONDOWN – Fare tuşlarından herhangi birine basıldığı zaman oluşur.
VIDEORESIZE – Pencere boyutu değiştiği zaman oluşur.
USEREVENT – Bu olay tipi kullanıcı tanımlı olaylarda kullanılır.

Tabii ki type niteliği bir string veri tutmaz. QUIT, KEYUP gibi değişkenler integer veri tutarlar. Bu değişkenlere pygame i import ettikten sonra pygame.OLAYTIPI şeklinde erişebilirsiniz…

from pygame.locals import *

Bu şekilde ki bir içe aktarma yöntemiyle pygamede ki bütün tanımlı değişkenlere direkt adıyla erişebilirsiniz.

Her Event() fonksiyonunun birer “type” adında niteliği olduğunu söylemiştik. Her farklı olay tipinin kendine has nitelikleride vardır. Bunları da diğer fonksiyonlarla beraber öğreneceğiz.

Pygame de penceredeki güncellemeleri almak için while döngüsü kuruyoruz. Biz pencereye bakarken fark etmesekte ekran sürekli güncellenir. Pencereye odaklı iken bastığımız bir klave tuşu veya fare hareketi bir olay meydana getirecektir. Bu olay o anki döngü tamamlanıp yenisi başladığında listeye alınır ve o olayın kontrolünü yaptıysak olay kontrol noktasında yakalanır. Biz bu olay listesine get() fonksiyonuyla ulaşırız. Bu method gerçekleşen olayların bir listesini döndürür.

import pygame

pygame.init()

pencere = pygame.display.set_mode((300,300))

while True:
    print pygame.event.get()

    pygame.display.flip()

Bu kodu çalıştırırsanız çok hızlı olarak konsol çıktısında olay listesi yazılır. Eğer gözleriniz yakalayabilirse konsola bakarken pygame penceresine fare ile tıklayın, klavyeden rasgele bir tuşa basın veya farenizi pencere üzerinde gezdirin. Akıp giden çıktılardan oluşan olayları görebilirsiniz. Yalnız bu durumda pencerenizi kapatmak biraz zorlayabilir sizi, uyarmadı demeyin…

Biz bu fonksiyonu genel olarak kullanıldığı şekliyle; for döngüsü ile kullanacağız ve olayları kontrol edeceğiz. Önceki derslerde mevcut olan pencere kapatma olayını kontrol eden kodumuza bir bakalım.

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pygame.display.flip()

Burada get() fonksiyonu ile listesi alınan olayları for döngüsüyle tek tek sıralıyoruz. if blokuyla da diyoruz ki; “Eğer Event() fonksiyonunun tipi, QUIT ile eşit ise sys.exit() ile uygulamayı kapat.” Eğer biz pencerenin üstündeki X butonuna basarsak oluşacak olayın tipi QUIT ile eşit olacaktır ve kodumuz bu şekilde ise pencere kapanacaktır. Aksi halde X butonuna sürekli bassanız da pencere kapanmaz.

Bazı uygulamalarda dialog pencerelerine odaklıyken escape(ESC) tuşuna bastığımızda pencere kapanır. Böyle bir şeyi pygame de uygulamak istersek şöyle yaparız.

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

while True:
    for i in pygame.event.get():
        if i.type == pygame.KEYDOWN:
            if i.key == pygame.K_ESCAPE:
                sys.exit()

    pygame.display.flip()

Bu kodda ise tipi KEYDOWN ile eşit olan olay varsa alttaki işlemleri gerçekleştir dedik. Gelen olayın tipi KEYDOWN ile eşit ise bu Event() fonksiyonla “key” niteliğide gelir. key niteliğinin escape tuşunun yerini tutan K_ESCAPE değişkenine eşit olması durumunda uygulamayı kapatmasını söyledik.

Event() fonksiyonunun tipi KEYDOWN ise barındırdığı “key” niteliğiyle beraber “mod” ve “unicode” niteliklerini de barındırır. “mod” niteliğinin ne işe yaradığını hiç gerek duymadığımdan bilmediğim için değinmeyeceğim, ama “unicode” niteliğine ileriki derslerde değineceğim. Bu konuda önemli olan, olayları kavrayabilmemizdir.

Değinmek istediğim başka bir nokta ise şudur. Her Event() fonksiyonu bir type niteliği barındırır ve biz bu type niteliğinin değerine göre olay kontrolünü yaparız. Mesela MOUSEBUTTONDOWN tipinde olan bir Event() fonksiyonu “pos” ve “button” niteliklerinide barındırır, ama KEYDOWN tipinde olan bir Event() fonksiyonu “key”, “unicode” ve “mod” niteliğini barındırır. Bu yüzden kodlarken önce olayın tipini kontrol ediyoruz ki diğer nitelikleri kullanırken emin olabilelim. Yoksa olmayan bir niteliği if ile kullandığımızda AttributeError hatası alırız.

Pencere modunda bir oyun yaptınız ve fare oku bu oyunu oynarken sürekli ekrandan dışarı çıkıyor. set_grap() fonksiyonuyla giriş ve çıkış aygıtlarını pencereye kitleyebiliriz. Bu fonksiyona True argümanını verirseniz fare oku ekrandan dışarı çıkamayacaktır.

import pygame, sys

pygame.init()
pencere = pygame.display.set_mode((300,300))

pygame.event.set_grab(True)
while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()
        if i.type == pygame.KEYDOWN:
            if i.key == pygame.K_ESCAPE:
                sys.exit()

    pygame.display.flip()

Bu kod fare imlecini pygame penceresinden çıkmamasını sağlar. Bu yüzden fare imlecini X butonuna tıklatamayacağınız ya da başka bir şey yapamayacağınız için ESC tuşuna uygulamayı kapatma görevi verdik. Bu sayede uygulamayı kapatma zorluğu çekmeyeceğiz.

Olayları kontrol edebildiğimiz gibi kullanıcı tanımlı olaylar da oluşturabiliriz. Yukarıda USEREVENT değişkenini tanıtırken kullanıcı tanımlı olaylarda kullanıldığını söylemiştik. pygame.event modülünün Event() fonksiyonunu kullanarak kendi olay fonksiyonumuzu oluşturabiliriz.

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

can = 100
can_event = pygame.USEREVENT+1

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()
        if i.type == pygame.KEYDOWN:
            if i.key == pygame.K_UP:
                pygame.event.Event(can_event, can=-10)

    pygame.display.flip()

Bu örnekte can değişkeni oluşturup değerini 100 verdik. can_event değişkenine ise kullanıcı tanımlı olay olan USEREVENT ın değerine bir artırıp yeni değeri atadık. USEREVENT 24 sayısını tutar ve 24 sayısından sonraki değerler USEREVENT olarak değerlendirilir.

Olay kontrolünde ise klavyeden yukarı ok tuşuna basıldığı zaman tanımladığımız Event() fonksiyonu olayımız olacaktır. Bu olayın tipi can_event a eşit olacaktır ve type niteliğiyle beraber can adında bir nitelikte gelecektir. Bu nitelik bizim kodumuzda -10 değerini taşıyacaktır.

Bu kod bu halde işe yaramaz. Biz altına bir if bloku ekleyip bu olayı yakalamaya çalışsak dahi yakalayamayız. Çünkü bu halde gelecek döngüdeki olay listesinde yer almayacaktır. Yer alması için post() fonksiyonuyla olay listesine aktarmamız gereklidir. Kodumuzun çalışır hali şöyle olacaktır.

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

can = 100
can_event = pygame.USEREVENT+1

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()
        if i.type == pygame.KEYDOWN:
            if i.key == pygame.K_UP:
                event = pygame.event.Event(can_event, can=-10)
                pygame.event.post(event)
        if i.type == can_event:
            can = can + i.can
            print can

    pygame.display.flip()

Bu örnekte Event fonksiyonumuzu oluşturduktan sonra post() fonksiyonuyla listeye aktarma yaptık. Eğer bu kodu çalıştırırsak; yukarı ok tuşuna basılınca can_event olayı oluşacak ve bir sonraki dögü sırasında if bloku bu olayı yakalıyacaktır ve can değişkeniyle Event() fonksiyonunun barındırdığı can niteliğindeki değeri toplayıp print ile yazdıracaktır. Örneğimizde can niteliği -10 değerinde olduğu için ilk yukarı ok tuşuna bastığımızda çıktımız 90 olacaktır. Ne kadar basarsak her seferinde can değişkeninin değeri -10 artacaktır.

pygame.event modülü bunlardan başka da fonksiyonlara sahiptir, ama biz sık kullanacağımız fonksiyonları öğrendik ve ilerideki derslerde ihtiyaç duyarsak bu fonksiyonlarıda o derslerde öğrenebiliriz. Bu ders belki çok açıklayıcı yada öğretici olmamış olabilir, ama bu derste event modülünün temelini kavramış olmalıyız. Gerekli modülleri öğrenipte uygulamalı derslere başladığımızda kavrayamadığımız noktalarıda kavramış olacağımıza inanıyorum. Bu derslerde gösterilenleri deneyerek ve üzerlerinde değişikler yaparak neyin nasıl olması gerektiğini öğrenmeye çalışırsanız bu bilgiler aklınıza kazınacaktır…

Yazım hatası varsa bildiriniz.
Bu yazı Creative Commons-BY-SA ile lisanslanmıştır. Bu yazıyı ilk sahibini belirtmek ve aynı lisansla dağıtmak koşuluyla kullanabilirsiniz.

Benzer Yazılar:

  1. Pygame ile Oyun Programlama – Image Modülü
  2. Pygame ile Oyun Programlama – Display Modülü
  3. Pygame ile Oyun Programlama – Surface Modülü
  4. Pygame ile Oyun Programlama – Draw Modülü
  5. Pygame ile Oyun Programlama – Font Modülü
21
Tem

Pygame font modülü, bir Surface nesnesinin içine TrueType yazı tiplerini işlemek için izin verir. Ekrana yazdıracağımız yazıları Font nesnesiyle oluştururuz ve Font nesnesiyle yazılarımızı işleriz. Örneğin, ekrana “Yeni Oyun” yazdıracağız ve bunun altı çizili ve eğik olmasını istiyoruz. Font nesnesinin methodları vasıtasıyla bu isteğimizi gerçekleştiririz. Bir Font nesnesi şöyle oluşturulur:

yazi = pygame.font.Font(u"yazıtipi.ttf", 14)

Font nesnesinin ilk parametresi string olarak yazı tipi dosyasının adını ister. Eğer yazdığımız kodla yazı tipi aynı dizinde ise sadece adını yazmamız yeterli. Farklı bir dizindeyse tam yolunu yazmamız gerekir.

Bu halde yukarıdaki kod bize Font nesnesi döndürür. Biz ekrana Surface çizdirebildiğimizden bize lazım olan şey bir Surface nesnesi. Yukarıdaki koda bakarsak biz sadece yazı tipiyle yazının pixel olarak büyüklüğünü girdik, ama yazdıracağımız yazıyı henüz girmedik. Şuna bir bakalım:

yazi = pygame.font.Font(u"yazıtipi.ttf", 14)
surface = yazi.render(u"Yeni Oyun", True, (255,255,255), None)

Font nesnesinin render() methodu, bizden gerekli bilgileri alıp bir surface nesnesi döndürür. Biz bu kodda “Yeni Oyun” kelimelerini yazdıracağımızı, True ile antialias olacağını, (255,255,255) ile yazı renginin beyaz olacağını söyledik. None parametresi ise yazının arkaplan renginin olmayacağını belirtir. Son parametre varsayılan olarak None dir. Yani yazmanıza gerek yoktur. Yani arkaplan rengi girmek istemiyorsanız bu kısmı atlayın.

Bizim ihtiyacımız olan Surface nesnesiydi ve render() methoduyla istediğimiz şekilde bir yazıyı Surface nesnesine çevirdik. Şimdi örnek bir kodla bunu ekrana yazdıralım.

#-*- coding:utf-8 -*-
import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

yazi = pygame.font.Font("akaDora.ttf", 20)
surface = yazi.render(u"Yeni Oyun", True, (255,255,255))

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pencere.fill((0,0,0))

    pencere.blit(surface, (100,100))
    pygame.display.flip()

Örneğimizde “akaDora.ttf” adlı yazı tipini kullandım ve karakterlerin boyutunu 20pixel büyüklüğünde olacak şekilde ayarladım. render() methodu ile de yumuşatmalı, beyaz renkte “Yeni Oyun” kelimeleriyle bir Surface nesnesi meydana getirdim ve surface değişkenine atadım. Daha önceki derslerde gördüğümüz gibi pencere yüzeyimizin blit() methoduyla 100×100 konumuza bu yazıyı yazdırdık. Ondan önce gelen fill() methodu da ekranımızı temizleyerek güncellenme olması durumunda oluşacak kirlenmeleri önlüyor.

Ekrana yazdırdığımız bir yazıyı eğik, kalın ve altı çizili yapabiliriz. Her biri için bir ayrı methodlar mevcuttur. Kavraması çok kolay olduğundan tek bir örnekte bu methodları öğrenelim.

#-*- coding:utf-8 -*-
import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

yazi = pygame.font.Font("GentiumPlus.ttf", 20)
yazi.set_bold(True)
yazi.set_underline(True)
yazi.set_italic(True)

surface = yazi.render(u"Yeni Oyun", True, (255,255,255))

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pencere.fill((0,0,0))

    pencere.blit(surface, (100,100))
    pygame.display.flip()

Bu örneğimizde bir Font nesnesi oluşturduk; set_bold() methoduyla yazdıracağımız yazıyı kalın, set_underline() methodu ile altı çizili, set_italic() methodu ile de eğik hale getirdik. render() methodu ile Surface nesnesine dönüştürdük. Dönüştürülen Surface nesnesini blit() ile ekrana 100×100 konumuna yazdırdık.

Yazdırdığımız yazının eğik mi, kalın mı, altı çizili mi olduğunu ise get methodlarıyla öğreniriz:

print yazi.get_bold()
print yazi.get_underline()
print yazi.get_italic()

Font nesnesinin render() methoduyla yazdıracağımız yazıyı Surface nesnesine dönüştürüldüğünü öğrendik. Her Surface nesnesinin bir uzunluğu ve yüksekliği vardır. Font nesnesinin get_height() methodu bize Surface nesnesinin yüksekliğini verir. get_linesize() methodu da genelde get_height() methodu ile aynı sayıyı döndürür.

Peki, bu get_linesize() methodu bizim ne işimize yarayabilir? Birden fazla yazıyı alt alta yazdırıyorsak, bu methodun döndürdüğü değeri, yazdırdığımız blit() methodunda verdiğimiz yükseklik değerine artı olarak eklersek orantılı bir görünüm elde ederiz.

#-*- coding:utf-8 -*-
import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

yazi = pygame.font.Font("akaDora.ttf", 20)
satir = yazi.get_linesize()

surface = yazi.render(u"Yeni Oyun", True, (255,255,255))

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pencere.fill((0,0,0))

    pencere.blit(surface, (100,100))
    pencere.blit(surface, (100,100+satir))
    pencere.blit(surface, (100,100+satir+satir))
    pygame.display.flip()

Örneğimizde “satir” değişkenine get_linesize() methodunun döndürdüğü değeri atadık ve oyun döngümüzde bunu kullandık. Aynı Surface nesnesini alt alta olacak şekilde yüksekliğine “satir” değişkeninide ekleyip orantılı olarak yazdırdık.

Font sınıfıyla hep aynı dizinde bulunan yazı tipi dosyalarını kullandık. Sistemde yüklü yazı tiplerini kullanmak istiyorsak sistemde yüklü bulunan yazı tipinin tam yolunu belirtmeniz gerekir. SysFont() fonksiyonu bizi uzun uzun yazı tipinin yolunu yazdırmak yerine sadece yazı tipinin adını yazmamızı istiyor. SysFont() girdiğimiz yazı tipi adını kontrol ediyor ve varsa bu yazı tipini kullanıyor. Ayrıca pratiklik amacıyla kalınlık ve eğiklik durumunu parametre olarak alıyor ve bize bir Font nesnesi döndürüyor. Bize kalan da bu Font nesnesini render() methoduyla Surface nesnesine dönüştürmek kalıyor.

Bir örnekle açıklayalım:

#-*- coding:utf-8 -*-
import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

yazi = pygame.font.SysFont("ubuntu", 30, 0, 1)
surface = yazi.render(u"Ubuntu yazı tipi.", True, (0,255,0))

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pencere.fill((0,0,0))

    pencere.blit(surface, (30,130))
    pygame.display.flip()

Örnekte SysFont() fonksiyonunu kullandık ve ubuntu.ttf yazı tipini kullanmasını, 40px büyüklüğünde olmasını ve kalın değil, ama eğik olmasını söyledik. SysFont() fonksiyonu bize Font nesnesi döndürdüğü için fazladan bir ekleme yapmadan render() methodumuzu aynen kullandık ve ekranın 30×130 konumuna yeşil renkte “Ubuntu yazı tipi.” yazısını yazdırdık.

Hızlı bir yazı yazdırma yöntemi olduğundan bu fonksiyonu kullanabilirsiniz…

Pygame, beraberinde kendi varsayılan yazı tipiyle gelir. Bu yazı tipinin adı “freesansbold.ttf”dir. Pygame’in kurulu olduğu dizine bakarsanız bu yazı tipini görebiliriniz. Varsayılan yazı tipini şöylede öğrenebiliriz:

print pygame.font.get_default_font()

Bu kod parçası size pygame in varsayılan yazı tipini döndürecektir.

Sistemde mevcut bütün yazı tiplerini görmek isterseniz de get_fonts() fonksiyonunu kullanabilirsiniz.

print pygame.font.get_fonts()
# ya da
for i in pygame.font.get_fonts():
    print i,
# Bu daha güzel bir çıktı verecektir.

Sistemdeki mevcut yazı tiplerini kullanmak istiyor, ama SysFont() fonksiyonunu kullanmak istemiyorsanız, SysFont() gibi yazı tipinin adını yazınca yolunu döndürecek bir fonksiyon gerekecek…

print pygame.font.match_font("ubuntu")
/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-L.ttf

Örnekte de görüldüğü gibi match_font() fonksiyonu ile “ubuntu” yazı tipini arattık ve bize dosya yolunun çıktısını verdi.

#-*- coding:utf-8 -*-
import pygame, sys

pygame.init()
pencere = pygame.display.set_mode((300,300))

yazi_tipi = pygame.font.match_font("ubuntu")
yazi = pygame.font.Font(yazi_tipi, 20)
surface = yazi.render(u"Yeni Oyun", True, (255,255,255))

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pencere.fill((0,0,0))

    pencere.blit(surface, (100,100))
    pygame.display.flip()

Bu koddaki gibi bir kullanımla yazı tipimizi kullanabiliriz. Eğer kullanacağımız yazı tipinin kalın ve/veya eğik bir yazı tipi olmasını istiyorsak match_font() fonksiyonunun ikinci ve üçüncü parametrelerine True veya False verebilirsiniz.

print pygame.font.match_font("ubuntu", bold=True, italic=True)
/usr/share/fonts/truetype/ubuntu-font-family/Ubuntu-BI.ttf
Yazım hatası varsa bildiriniz.
Bu yazı Creative Commons-BY-SA ile lisanslanmıştır. Bu yazıyı ilk sahibini belirtmek ve aynı lisansla dağıtmak koşuluyla kullanabilirsiniz.

Benzer Yazılar:

  1. Pygame ile Oyun Programlama – Image Modülü
  2. Pygame ile Oyun Programlama – Surface Modülü
  3. Pygame ile Oyun Programlama – Display Modülü
  4. Pygame ile Oyun Programlama – Draw Modülü
  5. Pygame ile Oyun Programlama – Giriş
18
Tem

Surface modülünü anlatırken pygame.image modülünüde kullanmıştık. Pygame içinde mevcut olan image modülü ile var olan bir resim dosyasını pygame penceresinde göstermek için yükleyip Surface nesnesi yapabilir ya da bir Surface yi resim dosyası olarak kayıt edebiliriz. Surface modülünü anlatırken bir resim dosyasının load() methodu ile yüklendiğini görmüştük. Bu method; jpg, png, gif(animasyonsuz), bmp, pcx, tga, tif, lbm, pbm, xpm uzantılı resim dosyalarını yükleyebilir. Bir Surface yi resim olarak kaydeden save() methodu ise; bmp, tga, png, jpeg uzantılı olarak kaydedebilir.

Peki bu save() methodunu ne amaçla kullanabiliriz? Oynadığımız bazı oyunlarda ekran görüntüsü almak için bir kısayol tuşu vardır. Bu tuşa bastığımızda oyun, o anda ki görüntüyü alır ve resim dosyası olarak kaydeder. Bu methodda bize bu imkanı sağlar.

#-*- coding:utf-8 -*-
import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

resim = pygame.image.load("sprite.png")
resim.set_colorkey((14,248,0))

resim_cek = False
while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()
        if i.type == pygame.KEYDOWN:
            if i.key == pygame.K_F10:
                resim_cek = True
        if i.type == pygame.KEYUP:
            if i.key == pygame.K_F10:
                resim_cek = False

    if resim_cek:
        pygame.image.save(pygame.display.get_surface(), "ekran_görüntüsü.png")

    pencere.fill((0,0,0))

    pencere.blit(resim, (100,100))
    pygame.display.flip()

Yukarıdaki örnekte bir resim dosyasını image modülünün load() methoduyla yükledik ve yüklenen resim bir Surface nesnesine dönüştüğü için set_colorkey() methoduyla resimdeki yeşil renkte olan arkaplanı şeffaf yaptık.  Oyun döngüsünde klavye olaylarını kontrol eden bir kod yazdık.

if i.type == pygame.KEYDOWN:
    if i.key == pygame.K_F10:
        resim_cek = True
if i.type == pygame.KEYUP:
    if i.key == pygame.K_F10:
        resim_cek = False

Bu kodda F10 tuşuna basıldığı anda resim_cek değişkeni True değeri alıyor. Tuşa basmayı bıraktığımızda ise False değerini alıyor. Ana döngüde ki;

if resim_cek:
    pygame.image.save(pygame.display.get_surface(), "ekran_görüntüsü.png")

kodumuz da resim_cek değişkeni True ise image modülünün save() methoduyla ana yüzeyin o anda ki görüntüsünü “ekran_görüntüsü.png” adıyla kodumuzun bulunduğu dizine kayıt ettiriyoruz.

Yalnız bu örnek kod mükemmel sayılmaz. Örneğin; biz her basışta tarih-saat.png formatında kayıt ediyorsak her F10 tuşuna basınca farklı isimlerle ekran görüntüsü oluşacaktır. Bu olağan bir durum, ama burdaki sorun klavye olayında ortaya çıkıyor. Kodumuzu inceleyecek olursak tuşa basıldığı an resim_cek değişkeni True değerini alacaktır ve ne kadar hızlı basıp çeksekte en kötü ihtimalle 3-4 kere döngü olacak ve bir basıçta birden fazla ekran görüntüsü kayıt edecektir. Bu durumda çöp resim dosyalarına yol açacaktır.  Bunu engellemek için daha uygun bir yol şöyledir:

#-*- coding:utf-8 -*-
import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

resim = pygame.image.load("sprite.png")
resim.set_colorkey((14,248,0))

resim_cek = False
while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()
        if i.type == pygame.KEYDOWN:
            if i.key == pygame.K_F10:
                resim_cek = True

    if resim_cek:
        pygame.image.save(pygame.display.get_surface(), "ekran_görüntüsü.png")
        resim_cek = False

    pencere.fill((0,0,0))

    pencere.blit(resim, (100,100))
    pygame.display.flip()

Dikkat ettiyseniz F10 tuşunun bırakılma olayını kaldırdık ve o olaydaki “resim_cek = False” kodunu if bloku altına aldık. Bu sayede siz istediğiniz kadar F10 tuşuna basılı tutsanız dahi resimi kaydettikten sonra resim_cek değişkeni False olacağından if bloku işlenmeyecektir.

Eventlarda her olay bir kere algılanır ve tekrar o olayı yakalamak için o olayı bırakıp tekrar olay yaratmalısınız. Daha anlaşılır bir ifadeyle F10 tuşuna basılı tuttuğunuz süre boyunca sadece ilk bastığınız anda olay oluşacaktır ve tekrar etmeyecektir. Tabii biz bu durumu tek satır bir kod ilavesiyle değiştirebiliriz, ama bunu event modülünü işleyeceğim derste anlatacağım…

Yazım hatası varsa bildiriniz.
Bu yazı Creative Commons-BY-SA ile lisanslanmıştır. Bu yazıyı ilk sahibini belirtmek ve aynı lisansla dağıtmak koşuluyla kullanabilirsiniz.

Benzer Yazılar:

  1. Pygame ile Oyun Programlama – Surface Modülü
  2. Pygame ile Oyun Programlama – Display Modülü
  3. Pygame ile Oyun Programlama – Draw Modülü
  4. Pygame ile Oyun Programlama – Giriş

Surface modülü pygame de en çok kullanılan modüldür. pygame.image.load() ile yüklediğimiz resimler, draw ve gfxdraw ile çizdirdiğimiz şekiller, font modülü ile yazdığımız yazılar… Hepsi Surface nesnesine dönüştürülür ve bu şekilde üzerinde işlem yapılır. Bu modülün en çok kullanılan methodlarını öğreneceğiz.

Örnek bir Surface nesnesi şöyle oluşurulur:

import pygame

pygame.init()

kare = pygame.Surface((100,100))

100×100 pixellik bir Surface nesnesi oluşturduk… Surface modülünü pygame.Surface şelinde çağırabileceğimiz gibi pygame.surface.Surface şeklinde de çağırabilirsiniz.

Bir Surface nesnesini ana yüzeye çizdirmek için blit() methodunu kullanırız. Bu method ilk parametresinde çizeceği yüzeyin örneğini ister. İkinci parametresinde ise yüzeyinin hangi konumuna çizeceğini söyleyecek iki elemanlı bir tuple veya liste bekler.

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))
kare = pygame.Surface((100,100))

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pencere.fill((255,255,255))
    pencere.blit(kare,(100,100))
    pygame.display.flip()

Örnek kodumuzda ana Surface nesnemiz “pencere” oluyor. pencere.blit(kare, (100,100)) ile “kare” örneğine atadığımız 100×100 pixellik bir Surface nesnesini 100×100 koordinatına çizdiriyoruz. Örnek kodda değişiklikler yaparak iyice kavrayabilirsiniz.

İleride göreceğimiz pygame.image modülünde resim dosyalarını yüklemeyi ve onları yönetmeyi öğreneceğiz. O zaman da yüklediğimiz her resim bir Surface nesnesi olacak. Bu yükleyeceğimiz resimleri daha hızlı ekrana çizilmesini sağlamak için convert() ve convert_alpha() methodlarını kullanıyoruz. Eğer resim dosyası alpha değeri içeriyor ise convert_alpha() methodunu kullanmalıyız. Yoksa convert() methodu yeterlidir.

import pygame, sys
pygame.init()

pencere = pygame.display.set_mode((300,300))

resim1 = pygame.image.load("seffaf_resim.png")
resim1.convert_alpha()
resim2 = pygame.image.load("normal_resim.png")
resim2.convert()

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pencere.blit(resim1, (10,10))
    pencere.blit(resim2, (100,100))
    pygame.display.flip()

Örneğimizde şeffaflık içeren resim için convert_alpha() methodunu, şeffaflık içermeyen resim için convert() methodunu kullandık ve pencere.blit() ile ayrı ayrı çizdirdik. Bu örnekte resim dosyalarını kendiniz seçerek sonuçları inceleyebilirsiniz.

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

kare = pygame.Surface((100,100))
kopya_kare = kare.copy()

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pencere.fill((255,255,255))

    pencere.blit(kare,(100,100))
    pencere.blit(kopya_kare,(0,100))
    pygame.display.flip()

Bazı durumlarda bir Surface nesnesini kopyalama ihtiyacı duyabiliriz. copy() methodu Surface nesnesinin bir kopyasını döndürür. Biz yukarıdaki kodda “kopya_kare” örneğimize “kare.copy()” ile “kare” örneğinin bir kopyasını “kopya_kare” örneğine aktarmış olduk. Kopyalanan bir Surface nesnesinde yapılan değişiklikler kopya Surface nesnesini etkilemeyeceği gibi tam tersi durumda da etkilemez. Eğer biz yukarıdaki;

kopya_kare = kare.copy()

…satırını,

kopya_kare = kare

…yapsaydık; herhangi bir örneğimizde yapacağımız değişiklik her iki örneğide etkileyecekti. Bunu test ederek daha iyi kavrayabilirsiniz.

Üstteki kodumuzda da kullandığımız fill() methodu Surface nesnemizi belirttiğimiz renkle boyar. Mesela biz yukarıdaki kodda pygame penceresini beyaz renkte boyamasını sağlıyoruz. Bu methodu sadece rengini belirtmekte kullanmıyoruz. Ana Surface nesnemiz olan “pencere” ye çizdirdiğimiz bir çok nesnenin pozisyon değişikliklerinde oluşacak kirlenmeleri temizlemeye yarar. İleriki derslerde daha açıklayıcı anlatılacaktır.

Sprite animasyonlu bir oyun yapmayı planlıyorsunuz ve araştırmanız sonucu istediğin Sprite resmini buldunuz, ama baktınız ki resim dosyasındaki çizimlerin arkaplanı şeffaf değil ve bunu ekrana çizdirdiğinizde arkaplan rengide ekrana basılacaktır. Bu durumda çok kötü bir görünüm elde etmiş olacaksınız. Bu durumdan kurtulmak için Surface modülü set_colorkey() methodunu içerir.

import pygame, sys

pygame.init()
pencere = pygame.display.set_mode((300,300))

resim1 = pygame.image.load("sprite.png")
resim2 = resim1.copy()
resim2.set_colorkey((14,248,0))

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pencere.blit(resim1, (10,10))
    pencere.blit(resim2, (100,10))
    pygame.display.flip()

Örneğimizde “sprite.png” adında bir resim dosyasını yükledim ve “resim2″ değişkenine kopyasını aldım. Bu kopya Surface nesnemizin (14,255,0) renk koduna denk gelen pixelleri şeffaf yapmasını set_colorkey() methoduyla sağladım ve her iki resmi de öncesi ve sonrası gibi ekrana çizdirdim. Örnek resimle yaptığım bu uygulamanın ekran görüntüsünü de görebilirsiniz.

print resim2.get_colorkey()

Bu kodla da set_colorkey() methoduyla şeffaflaştırılan renk kodunu tuple olarak alabilirsiniz.

Surface nesnesine şeffaflık vermek isteyebilirsiniz. Bunu yapmak için Surface modülünün set_alpha() methodunu kullanmalısınız. Bu method integer olacak şekilde tek bir parametre alır. Bu parametreyi 0-255 sayıları arası bir değer verebilirsiniz. Sıfıra yakın olan değerlerde şefaflık üst düzeyde olacaktır. Yüksek değer girişlerde ise matlık oranı yükselecektir.

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

resim1 = pygame.image.load("sprite.png")
resim2 = resim1.copy()
resim1.set_alpha(120)

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pencere.fill((0,0,0))

    pencere.blit(resim1, (10,10))
    pencere.blit(resim2, (100,10))
    pygame.display.flip()

Şeffaflık olsun ya da başka bir şey, ana yüzeyi temsil eden Surface nesnesi fill() methoduyla temizlenmelidir. Aksi halde yukarıda ki koddan bu kısmı çıkarırsanız resmin şeffaflığı görülmeyecektir. Ekranı temizleyen ve boyayan fill() methodu olmadığı için yapılan her şey üst üste çizilecek ve kat kat çizilen resim mat görünecektir.

Eğer set_alpha() methoduyla şeffaflık verdiysek ya da Surface nesnemizi convert() veya convert_alpha() methodlarıyla dönüştürmemişsek get_alpha() methodu şeffaflık varsa değerini döndürecektir.

Bir Surface nesnesinin uzunlukxyükseklik bilgisini öğrenmek istiyorsak get_size() methodunu kullanırız. Bu method (uzunluk, yükseklik) formatında değer döndürür. Eğer uzunluğu ayrı, yüksekliği ayrı almak istersek uzunluk için get_width() methodu, yükseklik için ise get_height() methodunu kullanırız.

Her Surface nesnesi görünüşte olmasa da temelde dikdörtgen bir alanı kaplar. get_rect() methodu Surface nesnesinin ekrandaki yerini ve boyutunu belirten bir Rect nesnesi döndürür. Eğer,

print pencere.get_rect()

kodunu yukarıdaki örneklerden birine yazarsanız ana yüzeyin Rect bilgisinin çıktısını alırsınız:

<rect(0, 0, 300, 300)>

Bir Surface yi hangi konuma çizdirseniz çizdirin, konum bilgisini veren ilk iki parametre sıfır olacaktır. Biz bu Surface yi blit() methodu ile çizdirdiğimizde blit() methodu bize get_rect() methodunda olduğu gibi Rect nesnesi döndürecektir ve…

pencere.blit(resim1, (10,10))

kodunun çıktısı “” olacaktır. Bu çıktıdan anlayacağınız blit() methoduyla hangi konuma çizdirirsek dönen rect nesnesinde konum bilgiside o olur.

Uygulamalı dersler başladığı zaman Rect nesnesini daha iyi anlayacağız ve yazacağımız oyunlarda nesne hareketlerinde çokça kullanacağız…

Yazım hatası varsa bildiriniz.
Bu yazı Creative Commons-BY-SA ile lisanslanmıştır. Bu yazıyı ilk sahibini belirtmek ve aynı lisansla dağıtmak koşuluyla kullanabilirsiniz.

Benzer Yazılar:

  1. Pygame ile Oyun Programlama – Display Modülü
  2. Pygame ile Oyun Programlama – Draw Modülü
  3. Pygame ile Oyun Programlama – Giriş
15
Tem

Pygame draw modülüyle geometrik şekiller çizebiliriz. Bu modülle; dikdörtgen, daire, elips, çokgen, çizgi, ve yay-kavis çizebiliriz. Çizgi çizimlerinde ise artı olarak antialias çizgiler çizebiliriz. Antialias, şekillerin kenarlarındaki kırıklığı yumuşatarak daha iyi görünüm elde edilmesini sağlar. Diğer geometrik şekillerde bu özelliği kullanmak istiyorsanız pygame’in gfxdraw modülünü kullanmanız gerekecektir. Yalnız gfxdraw modülünde bir geometrik şeklin kenar kalınlığını ayarlıyamıyoruz. Bu modülü kullanacaksanız bunuda göz önüne almalısınız.

Dikdörtgen Çizdirme

Pygame de bir kare veya dikdörtgen çizdirmek istiyorsak draw modülünün rect() methodunu kullanabiliriz. Rect, rectangel sözcüğünün kısaltmasıdır. Türkçe de dikdörtgen anlamındadır. rect() methodu dört parametre alır; dikdörtgenin çizileceği yüzey nesnesi, rengi, konum ve boyutu, kalınlığı. Aşağıda ki örnek kodumuzla da pratik yapalım.

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

beyaz = (255,255,255)

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pygame.draw.rect(pencere, beyaz, (50,50,100,150), 1)

    pygame.display.flip()


Yazdığımız kodla 300×300 pixellik bir pencere oluşturduk. Bu pencerede gerçekleşebilecek hareketler için bir döngü oluşturduk. Döngümüzde rect() methodunu kullanarak ana yüzeye beyaz renkte, bir pixel kalınlığında kenarı olan bir dikdörtgen çizdirdik. Bu dikdörtgenin boyutunu 100×150 olarak ayarladık ve pozisyonunu 50×50 yaptık.

Çokgen Çizdirme

Polygon ya da çokgen, çok köşeli geometrik şekillere verilen addır. polygon() methodumuz la istediğimiz sayıda kenarı olan bir şekil çizdirebiliriz. Ben bu örnekte ikizkenar üçgen çizdireceğim…

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

yesil = (0,255,0)

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pygame.draw.polygon(pencere, yesil, [(100,100),(100,200),(200,200)], 1)

    pygame.display.flip()

Bir pencere oluşturduk ve ana döngümüzde üçgen çizdireceğimiz polygon() methodunu yazdık. İlk parametremizde çokgeni hangi yüzeye çizdirileceğini söyledik. Çokgenimizin yeşil renkte ve son parametre olarak verdiğimiz değerin de kenar kalınlığı olarak 1 pixel olmasını istedik. Liste içinde verdiğimiz konum bilgileriyle bir konumdan diğerine son konumdan ilk konuma çizgi çizdirilmesini sağladık. Verdiğimiz konum bilgileriyle ikizkenar üçgen çizimi yapmış olduk.

Liste olarak verdiğimiz konum bilgilerini artırarak daha fazla kenarı olan şekiller çizdirebiliriz. Son parametre olan kenar kalınlığını 0(sıfır) verirsek şeklin içini girdiğimiz renkle doldurur. Kalınlığı çok artırırsakta birleşme noktalarında kırıklar meydana gelecektir.

Daire Çizdirme

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

kirmizi = (255,0,0)
pozisyon = (150,150)
yaricap = 100
kalinlik = 1

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pygame.draw.circle(pencere, kirmizi, pozisyon, yaricap, kalinlik)

    pygame.display.flip()

Daire çizdirmek için örnek kodda da görüldüğü gibi circle() methodunu kullanıyoruz. Daha açıklayıcı olsun diye parametrelere girilen değerleri değişkenlere atadım. Bir daire çizdirmek için circle() methodu, bizden yarıçap bilgisi ister; yariçap değerini biz 100 olarak verdik. Bu durumda bu dairenin çapı 200 pixel uzunluğunda olacaktır. Pozisyon olarak verdiğimiz değer dairenin sol-üst köşesini işaret eder. Bu konum dairenin sol ucuyla üst ucunu, sol-üst tarafta birleştiği noktadır. Daha iyi anlamak için örnek uygulamamızda değişiklikler yapıp denemeniz iyi olur.

Kalınlık değerini yine 1 pixel olarak verdik. Eğer 0 verseydik dairenin içi kirmizi renkle doldurulacaktı. Kalınlığı fazla arttırdığımızda ise fark edeceksiniz ki çizgi arasında boş pixeller görünecektir. Bunu istemiyorsanız kalınlığı düşük tutmanız yerinde olur.

Yumuşatma olmadığından dairenin etrafını çeviren kenarında kırık pixeller görünür. Güzel görünüm elde etmek için pygame.gfxdraw modülünden yardım almalısınız…

Elips Çizdirme

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

mavi = (0,0,255)

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pygame.draw.ellipse(pencere, mavi, (50,50,80,120), 1)

    pygame.display.flip()

Yukarıdaki örnekte 50×50 konumunda 80×120 boyutunda ve 1 pixel kalınlığında kenarı olan mavi bir elips şekli çizdirdik. ellipse() methodu, rect() methoduyla aynı parametreleri alır, ama ekrana çizilen elips bir şekildir.

Daire gibi elips şeklininde kenarında kırıklar oluşur. Hoş görünmeyen bu durumu pygame.gfxdraw modülü ile halledebiliriz

Eğik-Kavis Çizdirme

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

yesil = (0,255,0)

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pygame.draw.arc(pencere, yesil, (10,10,100,100), 0, 4, 1)

    pygame.display.flip()

arc() methodu elips şeklinde eğik-kavisli çizgiler çizmemizi sağlar. Tam bir elips yerine belirttiğimiz açılara göre eğik çizgi çizebiliriz. arc() methodu altı parametre alır. İlk parametremiz kavisin çizileceği yüzeyi belirtir. İkinci parametre çizimin rengini, üçüncüsü ise rect yani dikdörtgen alanını belirtir. Methodumuz verilen konumdan dikdörtgen bir alana eğik çizgi çizer. Dördüncü parametremiz başlangıç açısını belirtir. Eğer 0 yazarsak matematik derslerinde öğrendiğimiz gibi elipsin sağ-orta noktasını başlangıç olarak alır. Beşinci parametre ise bitiş açısını belirtir. Buraya 6.30 değerini girersek tam bir elips çizer. Bitiş açısı en fazla 6.28-30 olmalıdır. Bu tam bir dönüşümün değeridir. Daha yüksek bir değer girilse de etkilemez. Son parametremizde çizimin kalınlığını belirtir.

Düz Çizgi Çizdirme

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

beyaz = (0,0,255)

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pygame.draw.line(pencere, (0,255,0), (75,75), (150,150), 1)

    pygame.display.flip()

Düz çizgi çizmek için line() methodunu kullanırız. Yukarıdaki örnek kodu çalıştırdığınızda; yeşil renkte, bir pixel kalınlığında, 75×75 konumundan 150×150 konumuna düz bir çizgi olduğunu görürsünüz.

Çoklu Düz Çizgi Çizdirme

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

beyaz = (0,0,255)

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pygame.draw.lines(pencere, (66,99,200), True, [(100,100),(100,200),(200,100)], 1)

    pygame.display.flip()

lines() methodu verdiğiniz konum noktaları listesini baz alarak çizgiler çizer. Eğer üçüncü parametreyi True verirseniz çizgiler en sona birleşmiyorsa ilk noktayla son nokta arasına bir çizgi çizerek kapatma yapar. False değeri verirseniz verdiğiniz listeye uyarak çizim işlemini yapar.

Yumuşatılmış Düz Çizgi Çizdirme

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

sari = (255,255,0)

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pygame.draw.aaline(pencere, sari, (100,100), (120,150), 0)

    pygame.display.flip()

aaline() methodu line() methoduyla hemen hemen aynıdır. Farkı ise, anti aliasing yani yumuşatma yapar. Örneğin çapraz bir çizgi çizdirdiğinizde line() fonksiyonu çizimi tırtıklı bir şekilde çizer ve göze hoş gelmez, ama aaline() pürüzsüz bir çizgi çizer. Ayrıca en sonraki parametre çizginin kalınlığını belirtmez. Son parametre -blend- True ya da False değeri alır. Son parametre False ise çizgide oluşabilecek kırık pixeller; renk tonuna uygun, çizgiye göre şeffaflık içeren pixellerle kapatılır. True değeri verilirse şeffaf pixeller yerine aynı renk pixellerle kapatılır.

Blend parametresi False


Blend parametresi True

Yumuşatılmış Düz Çizgiler Çizdirme

import pygame, sys

pygame.init()

pencere = pygame.display.set_mode((300,300))

mavi = (0,0,255)

while True:
    for i in pygame.event.get():
        if i.type == pygame.QUIT:
            sys.exit()

    pygame.draw.aalines(pencere, mavi, True, [(100,100),(100,250),(200,100)], 1)

    pygame.display.flip()

aalines() methodu da lines() methoduyla aynıdır. aaline() methodun da olduğu gibi çizgilerde yumuşatma yapar. Son parametresi de -blend- çizginin kalınlığını değil çizimin güzelliğini belirtir. True değeri verilirse birbirleriyle birleşen çizgilerin kesiştiği noktalar düzgün görünür. False değeri verilirse kesişen noktalarda çıkıntılar oluşur. Deneyerek tam olarak nasıl olduğunu anlayabilirsiniz.

Yazım hatası varsa bildiriniz.
Bu yazı Creative Commons-BY-SA ile lisanslanmıştır. Bu yazıyı ilk sahibini belirtmek ve aynı lisansla dağıtmak koşuluyla kullanabilirsiniz.

Benzer Yazılar:

  1. Pygame ile Oyun Programlama – Display Modülü
  2. Pygame ile Oyun Programlama – Giriş
13
Tem

Display modülü pencere oluşturmayı ve onu kontrol etmemizi sağlayan methodlar sunar. Bu yazı da display modülünün işimize yaran methodlarını öğreneceğiz.

Pencere Oluşturma

Pygame de bir pencere oluşturmak için display modülünün set_mode() methodunu kullanırız. Bu set_mode() methodu üç adet parametre kabul eder, ama ilk iki parametresi işimizi görmemize yeterlidir.

import pygame
import sys

pygame.init()

pencere = pygame.display.set_mode((200,200), pygame.SWSURFACE)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    pygame.display.flip()

Bu örneğimizde 200×200 pixellik bir pencere oluşturmuş oluyoruz. Bunu sağlayan set_mode() methodunun ilk parametresidir. Bu parametre, pencere boyutunu belirten iki elemanlı liste kabul eder. İkinci parametremiz penceremiz için bayrak atamamıza izin verir. Örnek kodumuzdaki SWSURFACE değişkeni pygame in hafıza olarak video hafızasını kullanmasını söyler.

Pygame de bazı modülleri kullanabilmek için o modülleri başlatmamız gerekir. Bu işi pygame.init() kodu gerçekleştirir. Bu kodu yazmaz isek yukarıdaki kodu örnek alarak display modülünü başlatmamız gerekirdi. Bu durumda pygame.init() yerine pygame.display.init() kodunu yazmamız gerekir. init() fonksiyonu kullanılmaz ise kod hata verecektir.

pygame.display.quit() ise display modülü kapatır.

Bayrak olarak kullanabileceğiniz diğer değişkenler şunlardır:

  1. pygame.FULLSCREEN ekranı tamamen kaplar.
  2. pygame.HWSURFACE Donanım hızlandırması yapar. FULLSCREEN ile kullanılması gerekiyor.
  3. pygame.RESIZABLE pencere boyutunu değiştirebilmenizi sağlıyor.
  4. pygame.NOFRAME pencere kenarlıklarını kaldırır.
  5. pygame.DOUBLEBUF Ne işe yaradığından emin değilim, ama HWSURFACE veya OPENGL ile kullanmanız öneriliyormuş.
  6. pygame.OPENGL OpenGL renderli görüntü oluşturmanızı sağlar.
  7. pygame.SWSURFACE Sistem belleği yerine video hafızasını kullanır.

Pencere Yüzeyi

set_mode() methodu pencere oluşturmakla beraber bir Surface(yüzey) nesnesi döndürür. Bu dönen nesnenin örneğini alabileceğimiz gibi get_surface() methodunu da kullanabiliriz.

pencere = pygame.display.set_mode((200,200), pygame.SWSURFACE)
print pygame.display.get_surface(), pencere

pencere adlı örneğimizin çıktısıyla pygame.display.get_surface() in çıktısı aynı olacaktır. Bu Surface nesnesi ekrana çizdireceğimiz şekillerin çizileceği yüzeyi temsil eder. İleri ki yazılarımda Surface modülünüde öğrendiğimiz zaman daha iyi kavrayacaksınız. Bu modül pygame in yapı taşıdır desem yalan söylemiş olmam herhalde.

Ekran Modları

Oyun oynayanlardansanız mutlaka çözünürlük ayarı yapmışsınızdır. Ör: 800×600. Bu ayarı yaparken çeşitli çözünürlük oranlarıyla karşılaşırız. Eğer sizde çözünürlük seçeneğine göre ekranınızı çizdirmek istiyorsanız list_modes() methodunu kullanabilirsiniz. Bu methodu print ile yazdırdığımızda şöyle bir çıktı alırız:

[(1440, 900),
(1280, 800),
(1152, 864),
(1024, 768),
(832, 624),
(800, 600),
(700, 525),
(640, 480),
(512, 384),
(400, 300),
(320, 240)]

Bende ki çıktı böyle. Bu çıktıya bakarak ben yazdığım oyunda en düşük ekran boyutunu 320×240 en yüksek ekran boyutunu 1440×900 olarak sunabilirim. Tabii bunu kullanacaksak ona göre kodlarımızı yazmalıyız. Eğer 200×200 pixellik bir oyun ekranında örnek bir haritayı 200×200 olarak çizdiriyorsak pencere boyutunu yükselttiğimizde sağ ve alt taraflar boşlukta kalacaktır.

Simge Durumuna Küçültmek

Pygame penceresini full ekran yaptığınızda ve her hangi bir klavye tuşuna pencereyi kapatma olayını atamadığınızda can sıkıcı bir durumla karşılaşabilirsiniz. Windowstaki deneyimime göre pencere full ekrandayken Alt+Tab tuşuyla başka pencereye geçebilirken, GNU/Linuxta hiç bir şekilde full ekrandan çıkamıyorsunuz. Tek çareniz ctrl+alt+f1-f7 kısayolarından birine basıp konsola düşmek ve bilginiz yeterliyse çalışan pencereyi öldürmek. Aksi halde blgisayar kasanızdaki küçük düğmeye basarak bilgisayarı yeniden başlatmanız gerekir. Eğer bunu tecrübe ettiğinizde kaydedilmemiş verileriniz varsa vay halinize.

Ayrıca ekranı kapatmak için gerekli klavye olayını atamış olsanızda oyun esnasında mola verip başka bir pencereye geçme durumunu göze almalısınız. iconify() methodu bu gibi durumlarda imdadımıza yetişiyor.

import pygame
import sys

pygame.init()

pencere = pygame.display.set_mode((200,200), pygame.FULLSCREEN)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LALT:
                pygame.display.iconfy()

    pygame.display.flip()

Olay modülü olan event’ı henüz görmedik, ama kısaca anlatacak olursak sol ALT tuşuna bastığımızda iconfy() methodumuzu tetiklemiş oluyoruz. Pygame penceresine atadığımız FULLSCREEN bayrağı penceremizi full ekran yapar. Biz, sol ALT tuşuna bastığımızda pygame penceresi simge durumuna küçülecektir.

Pencere Başlığı

Verdiğim örnek kodları çalıştırdığınızda pencere başlığının “pygame window” olduğunu göreceksiniz. Eğer istersek pencere başlığımızı değiştirebiliriz.

import pygame
import sys

pygame.init()

pencere = pygame.display.set_mode((200,200), pygame.SWSURFACE)
pygame.display.set_caption(u"Oyunumuzun Adı")

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    pygame.display.flip()

Çok basit bir şekilde set_caption() methoduyla Pencere başlığımızı değiştirmiş oluyoruz. Bu methodu döngü içinde kullanarak sürekli değişen bir başlıkta yapabiliriz… Bu sizin hayal gücünüze kalıyor.

pygame.display.get_caption() ile de pencere başlığını alabilirsiniz.
Başlık atarken kullandığımız “u” string değerini unicode yapar. Eğer Türkçe karakter kullanacaksanız bu gerekli. Python’un 3x versiyonlarında unicode desteği sağlandığı için u”" gibi bir yazım biçimi ortadan kalktı.

Full Ekran Yapma ve Full Ekrandan Çıkma

Pygame penceremizi bir klavye tuşuna basarak full ekran yapmak ve tekrar eski haline getirmek isteyebiliriz. toggle_fullscreen() methodu bu isteğimizi gerçekleştirecektir.

import pygame
import sys

pygame.init()

pencere = pygame.display.set_mode((200,200), pygame.SWSURFACE)

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LALT and event.key == pygame.K_RETURN:
                pygame.display.toggle_fullscreen()

    pygame.display.flip()

Burada ALT ve ENTER tuşlarına birlikte basıldığında penceremizi full ekran yapmasını sağlıyoruz. K_RETURN klavyemizdeki büyük enter tuşunu ifade etmektedir. Numpad de mevcut olan enter ise K_KP_ENTER olarak geçmektedir.

Full ekran yaptığımız da aynı tuşlara tekrar bastığımızda ise toggle_fullscreen() methodu pencereyi eski durumuna döndürecektir. Eğer penceremizi FULLSCREEN bayrağıyla başlatırsak tuşlara ilk basışımızda full ekrandan çıkar ve belirttiğimiz boyutta bir pencere halini alır.

Pencere İkonu

pygame.display.set_icon(pygame.image.load(“logo.png”))

Sıradan bir pygame penceresinde sol üst kısımda bulunan ikon ağzında joystick olan sarı bir yılan resmidir. Bu resmi de başlık gibi değiştirebiliriz. Aşağıdaki koda bir bakalım.

import pygame
import sys

pygame.init()

pencere = pygame.display.set_mode((200,200), pygame.SWSURFACE)
pygame.display.set_icon(pygame.image.load("resim.png"))

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    pygame.display.flip()

pygame.image.load() resim dosyasını yükler ve onu Surface nesnesine çevirir. set_icon() methodu da parametre olarak Surface nesnesi bekler. Bu şekildeki bir kod ile resim.png resmini pygame penceresinin sol-üst tarafında ikon olarak görürüz.

Ekranı Güncellemek

İlk verdiğimiz örnekte döngü içerisinde şu kodu yazmıştık:

pygame.display.flip()

Pygame de ekrana bir Surface nesnesi çizdirdiğimizde bu çizimi görebilmek için ekranın güncellenmesi gerekir. Bu method bu görevi üstlenir. Ekrandaki her değişikliği görebilmek için while döngüsüyle sonsuz bir döngü oluşturmalıyız.

Görsel programlama da çoğu zaman biz fark etmesekte bir döngü mevcuttur. Pygame bu döngünün kontrolünü bize bırakır. Bu durum bizi sıkıntıya sokabilir…

flip() methodu ile aynı işi yapan bir de update() methodu vardır. Bu methodu flip() methodundan ayıran şey ise parametre almasıdır. update() methoduna parametre vermezseniz flip() ile aynı işi görür, ama dikdörtgenlerden oluşan bir listeyi parametre olarak verirseniz bu dökdörtgenler güncellenir.

pygame.display.update([(10,10,100,100),
                       (200,140,200,200)])

Bu şekilde verilen bir parametrede update() methodu 10×10 konumundan başlayan 100×100 pixel boyutlarındaki dikdörtgen alanı günceller. Bu örnekte verdiğimiz dikdörtgen alanında Surface nesnesi mevcut olsaydı o nesnedeki değişiklikler güncellenmiş olacaktı.

Yazım hatası varsa bildiriniz.

Bu yazı Creative Commons-BY-SA ile lisanslanmıştır. Bu yazıyı ilk sahibini belirtmek ve aynı lisansla dağıtmak koşuluyla kullanabilirsiniz.

Benzer Yazılar:

  1. Pygame ile Oyun Programlama – Giriş
18
Ara

Matrix, Terminator, HAL, I Robot... Yapay zeka insanlığı esir edecek mi göreceğiz. Oyunda dünyadan gizlenmeye çalışan ama aynı zamanda kendisini geliştiren bir yapay zekayı canlandırıyoruz. Adı: Singularity, kıtalara ayrılmış dünya bizim gibi bir yapıyla karşılaşacak durumda değil, çalışmalarımızı önce kiralık sunucularda ardından kendi merkezlerimizde sürdürüyoruz. Sunucularınız hackerlar, bilim adamları yada devlet görevlileri tarafından açığa çıkartıldıkça hakkınızda şüphelenenler artıyor ve belli bir noktadan sonra dünya sizi farkedip yok edebiliyor. Edebiliyor diyorum çünkü oyunun sonunu görme fırsatım olmadı, bir sonu olup olmadığını bile bilmiyorum tüm dünya ile baş edebileceğini düşünen bir zeka varsa, buyursun. Kaynak kodu (1.3Mb) Güzel bir pygame uygulaması.