http___programarcadegames.com_index.php_chapter_introduction_to_sprites_lang_tr_2.xml
1.1 2.1 3.1 4.1 5.1 6.1 7.1 8.1 9.1 10.1 11.1 11.2 11.3 11.4 12.1 13.1 13.2 14.1 15.1 15.2 16.1 16.2 17.1 17.2 18.1 18.2 18.3 19.1 20.1 20.2 21.1 22.1 22.2 22.3 23.1 24.1 25.1 26.1 26.2 27.1 27.2 28.1 28.2 29.1 30.1 31.1 32.1 33.1 33.2 34.1 35.1 35.2 36.1 37.1 37.2 38.1 39.1 40.1 41.1 41.2 41.3 42.1 42.2 43.1 44.1 45.1 45.2 45.3 46.1 47.1 47.2 47.3 47.4 47.5 48.1 48.2 48.3 49.1 49.2 49.3 49.4 49.5 49.6 50.1 50.2 50.3 50.4 50.5 50.6 50.7 50.8 50.9 51.1 52.1 52.2 53.1 53.2 53.3 53.4 53.5 53.6 53.7 54.1 55.1 55.2 56.1 56.2 57.1 58.1 59.1 60.1 61.1 62.1 62.2 63.1 64.1 65.1 66.1 67.1 68.1 69.1 70.1 71.1 72.1 73.1
Program Arcade GamesWith Python And Pygame Chapter 19: Recursion A child couldn't sleep, so her mother told her a story about a little frog, who couldn't sleep, so the frog's mother told her a story about a little bear, who couldn't sleep, so the bear's mother told her a story about a little weasel... who fell asleep. ...and the little bear fell asleep; ...and the little frog fell asleep; ...and the child fell asleep. (Source: http://everything2.com/title/recursion) Recursion is an object or process that is defined in terms of itself. Mathematical patterns such as factorials and the Fibonacci series are recursive. Documents that can contain other documents, which themselves can contain other documents, are recursive. Fractal images, and even certain biological processes are recursive in how they work. 19.1 Where is Recursion Used? Documents, such as web pages, are naturally recursive. For example, Figure 19.1 shows a web document. That web document can be contained in a “box,” which can help layout the page as shown in Figure 19.2. This works recursively. Each box can contain a web page, that can have a box, which could contain another web page as shown in Figure 19.3. Recursive functions are often used with advanced searching and sorting algorithms. We'll show some of that here and if you take a “data structures” class you will see a lot more of it. Even if a person does not become a programmer, understanding the concept of recursive systems is important. If there is a business need for recursive table structures, documents, or something else, it is important to know how to specify this to the programmer up front. For example, a person might specify that a web program for recipes needs the ability to support ingredients and directions. A person familiar with recursion might state that each ingredient could itself be a recipes with other ingredients (that could be recipes.) The second system is considerably more powerful. 19.2 How is Recursion Coded? In prior chapters, we have used functions that call other functions. For example: def f(): g() print("f") def g(): print("g") f() It is also possible for a function to call itself. A function that calls itself is using a concept called recursion. For example: def f(): print("Hello") f() f() The example above will print Hello and then call the f() function again. Which will cause another Hello to be printed out and another call to the f() function. This will continue until the computer runs out of something called stack space. When this happens, Python will output a long error that ends with: RuntimeError: maximum recursion depth exceeded The computer is telling you, the programmer, that you have gone too far down the rabbit hole. 19.3 Controlling Recursion Depth To successfully use recursion, there needs to be a way to prevent the function from endlessly calling itself over and over again. The example below counts how many times it has been called, and uses an if statement to exit once the function has called itself ten times. 19.4 Recursion Factorial Calculation Any code that can be done recursively can be done without using recursion. Some programmers feel that the recursive code is easier to understand. Calculating the factorial of a number is a classic example of using recursion. Factorials are useful in probability and statistics. For example: = 10 \cdot 9 \cdot 8 \cdot 7 \cdot 6 \cdot 5 \cdot 4 \cdot 3 \cdot 2 \cdot 1$ Recursively, this can be described as: = \begin{cases} 1 & \text{if } n = 1, \\ n \cdot (n-1)! & \text{if } n > 1. \end{cases}$ Below are two example functions that calculate $n!$. The first one is non-recursive, the second is recursive. # This program calculates a factorial # WITHOUT using recursion def factorial_nonrecursive(n): answer = 1 for i in range(2, n + 1): answer = answer * i return answer # This program calculates a factorial # WITH recursion def factorial_recursive(n): if n == 1: return 1 elif n > 1: return n * factorial_recursive(n - 1) The functions do nothing by themselves. Below is an example where we put it all together. This example also adds some print statements inside the function so we can see what is happening. 19.5 Recursive Rectangles Recursion is great to work with structured documents that are themselves recursive. For example, a web document can have a table divided into rows and columns to help with layout. One row might be the header, another row the main body, and finally the footer. Inside a table cell, might be another table. And inside of that can exist yet another table. Another example is e-mail. It is possible to attach another person's e-mail to a your own e-mail. But that e-mail could have another e-mail attached to it, and so on. Can we visually see recursion in action in one of our Pygame programs? Yes! Figure 19.4 shows an example program that draws a rectangle, and recursively keeps drawing rectangles inside of it. Each rectangle is 20% smaller than the parent rectangle. Look at the code. Pay close attention to the recursive call in the recursive_draw function. """ Recursively draw rectangles. Sample Python/Pygame Programs Simpson College Computer Science http://programarcadegames.com/ http://simpson.edu/computer-science/ """ import pygame # Colors BLACK = (0, 0, 0) WHITE = (255, 255, 255) def recursive_draw(x, y, width, height): """ Recursive rectangle function. """ pygame.draw.rect(screen, BLACK, [x, y, width, height], 1) # Is the rectangle wide enough to draw again? if(width > 14): # Scale down x += width * .1 y += height * .1 width *= .8 height *= .8 # Recursively draw again recursive_draw(x, y, width, height) pygame.init() # Set the height and width of the screen size = [700, 500] screen = pygame.display.set_mode(size) pygame.display.set_caption("My Game") # Loop until the user clicks the close button. done = False # Used to manage how fast the screen updates clock = pygame.time. Clock() # -------- Main Program Loop ----------- while not done: for event in pygame.event.get(): if event.type == pygame.QUIT: done = True # Set the screen background screen.fill(WHITE) # ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT recursive_draw(0, 0, 700, 500) # ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT # Go ahead and update the screen with what we've drawn. pygame.display.flip() # Limit to 60 frames per second clock.tick(60) # Be IDLE friendly. If you forget this line, the program will 'hang' # on exit. pygame.quit() 19.6 Fractals Fractals are defined recursively. Here is a very simple fractal, showing how it changes depending on how “deep” the recursion goes. """ Sample fractal using recursion. Sample Python/Pygame Programs Simpson College Computer Science http://programarcadegames.com/ http://simpson.edu/computer-science/ """ import pygame # Define some colors black = (0, 0, 0) white = (255, 255, 255) green = (0, 255, 0) red = (255, 0, 0) def recursive_draw(x, y, width, height, count): # Draw the rectangle # pygame.draw.rect(screen,black,[x,y,width,height],1) pygame.draw.line(screen, black, [x + width*.25, height // 2 + y], [x + width*.75, height // 2 + y], 3) pygame.draw.line(screen, black, [x + width * .25, (height * .5) // 2 + y], [x + width * .25, (height * 1.5) // 2 + y], 3) pygame.draw.line(screen, black, [x + width * .75, (height * .5) // 2 + y], [x + width * .75, (height * 1.5) // 2 + y], 3) if count > 0: count -= 1 # Top left recursive_draw(x, y, width // 2, height // 2, count) # Top right recursive_draw(x + width // 2, y, width // 2, height // 2, count) # Bottom left recursive_draw(x, y + width // 2, width // 2, height // 2, count) # Bottom right recursive_draw(x + width // 2, y + width // 2, width // 2, height // 2, count) pygame.init() # Set the height and width of the screen size = [700, 700] screen = pygame.display.set_mode(size) pygame.display.set_caption("My Game") # Loop until the user clicks the close button. done = False # Used to manage how fast the screen updates clock = pygame.time. Clock() # -------- Main Program Loop ----------- while not done: for event in pygame.event.get(): if event.type == pygame.QUIT: done = True # Set the screen background screen.fill(white) # ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT fractal_level = 3 recursive_draw(0, 0, 700, 700, fractal_level) # ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT # Go ahead and update the screen with what we've drawn. pygame.display.flip() # Limit to 20 frames per second clock.tick(20) # Be IDLE friendly. If you forget this line, the program will 'hang' # on exit. pygame.quit() 19.7 Recursive Binary Search Recursion can be also be used to perform a binary search. Here is a non-recursive binary search from Chapter 15: def binary_search_nonrecursive(search_list, key): lower_bound = 0 upper_bound = len(search_list) - 1 found = False while lower_bound   key: upper_bound = middle_pos else: found = True if found: print( "The name is at position",middle_pos) else: print( "The name was not in the list." ) binary_search_nonrecursive(name_list,"Morgiana the Shrew") This same binary search written in a recursive manner: def binary_search_recursive(search_list, key, lower_bound, upper_bound): middle_pos = (lower_bound + upper_bound) // 2 if search_list[middle_pos]   key: binary_search_recursive(search_list, key, lower_bound, middle_pos ) else: print("Found at position", middle_pos) lower_bound = 0 upper_bound = len(name_list) - 1 binary_search_recursive(name_list, "Morgiana the Shrew", lower_bound, upper_bound) 19.8 Review 19.8.1 Short Answer Worksheet Click here for the chapter worksheet. You are not logged in. Log in here and track your progress. English version by Paul Vincent Craven Spanish version by Antonio Rodríguez Verdugo Russian version by Vladimir Slav Turkish version by Güray Yildirim Portuguese version by Armando Marques Sobrinho and Tati Carvalho Dutch version by Frank Waegeman Hungarian version by Nagy Attila Finnish version by Jouko Järvenpää French version by Franco Rossi Korean version by Kim Zeung-Il Chinese version by Kai Lin
1.1 2.1 3.1 4.1 5.1 6.1 7.1 8.1 9.1 10.1 11.1 12.1 13.1 14.1 15.1 16.1 17.1 18.1 19.1 20.1 21.1 22.1 23.1 24.1 25.1 26.1 27.1 28.1 29.1 30.1 31.1 32.1 33.1 34.1 35.1 36.1 37.1 38.1 39.1 40.1 41.1 42.1 43.1 44.1 45.1 46.1 47.1 48.1 49.1 50.1 51.1 52.1 53.1 54.1 55.1 56.1 57.1 58.1 59.1 60.1 61.1 62.1 63.1 64.1 65.1 66.1 67.1 68.1 69.1 70.1
Arcade Türü Oyun Programlamayıve Bilgisayar Bilimleri Öğrenin Chapter 14: Hareketli Grafiklere(Sprites) Giriş Sprite daha geniş bir sahnenin bir parçası olan iki boyutlu grafiktir. Genel olarak spritelar sahnede etkileşime geçilecek bazı nesne türleridir. Önceden, spritelar eski oyun konsollarının donanımları tarafından özellik olarak destekleniyordu. Bu özelleştirilmiş donanım desteği artık gerekmiyor, fakat bu kelime hala varlığını sürdürüyor. Pygame kütüphanesi spriteları destekliyor. Bu kod animasyon yönetiminde, çarpışma tespitinde ve sprite gruplarının yönetiminde yardımcı oluyor. 14.1 Basit Spritelar and Çarpışmalar Bu örnek siyah bloklar içeren ve fare ile kontrol edilen siyah bir blok yardımıyla onların toplanacağı bir ekranın nasıl oluşturulacağını gösteriyor. Program "skoru" kaç tane bloğun toplandığına göre tutuyor. Bu örneğin kodu şu adreste bulunabilir: http://cs.simpson.edu/index.php?chapter=example_code # Sample Python/Pygame Programları # Simpson College Bilgisayar Bilimi # http: cs.simpson.edu import pygame import random # Bazı renkleri tanımla black = ( 0, 0, 0) white = ( 255, 255, 255) red = ( 255, 0, 0) Pygame kütüphanesi sprite desteği için import edilir. Random kütüphanesi blokların rastgele yerleşebilmesi için import edilir. Renklerin tanımı standarttır; henüz bu örnekte yeni olan hiçbir şey yoktur. # Bu sınıf topu temsil ediyor # Pygame içerisindeki "Sprite" sınıfından türüyor class Block(pygame.sprite.Sprite): Bu kod Block sınıfının tanımını başlatıyor. 15. satırda bu sınıfın Sprite sınıfının bir alt sınıfı olduğuna dikkat edin. pygame.sprite. bu derste daha sonra tartışılacak olan kütüphaneyi ve paketi belirtiyor. Sprite sınıfının tüm varsayılan işlevselliği şu an Block sınıfının bir parçası durumunda. # Yapıcı. Rengi ve onun x ve y konumlarını # bloğa aktar def __init__(self, color, width, height): # Üst sınıfın (Sprite) yapıcı fonksiyonunu çağır pygame.sprite.Sprite.__init__(self) Block sınıfı için olan yapıcı fonksiyon self'i tıpkı diğer bütün yapıcı fonksiyonlar gibi bir parametre olarak alıyor. Ayrıca nesnenin rengi(color), yüksekliği(height) ve genişliğini(width) de parametre olarak alıyor. Sprite'ın içerisindeki ebeveyn sınıf yapıcı fonksiyonunu çağırmak spriteları başlatabilmeye imkan sağladığı için önemlidir. Bu satır 21'de yapılmıştır. # Bloğun bir resmini oluştur ve onu bir renkle doldur. # Bu aynı zamanda diskten yüklenen bir resim de olabilir. self.image = pygame.Surface([width, height]) self.image.fill(color) Bu kod aslında sonunda ekranda görünecek olan resmi oluşturuyor. 25. satır boş bir resim oluşturuyor. 26. satır onu siyah renkle boyuyor. Program siyah kareden başka bir şeye ihtiyaç duyarsa, bunlar değiştirilecek kod satırlarıdır. Örneğin, alttaki koda göz atın: self.image = pygame.Surface([width, height]) self.image.fill(white) self.image.set_colorkey(white) pygame.draw.ellipse(self.image,color,[0,0,width,height]) Bu kod bu şekilde değiştirilmiş olsaydı, her şey elips şeklinde olurdu. 25. satır elipsi boyuyor ve 26. satır beyazı saydam bir renk yapıyor. self.image = pygame.image.load("player.png").convert() self.image.set_colorkey(white) Eğer bunların yerine bit eşlemli bir grafik isteniyorsa, yukarıdaki kodları kullanmak bir grafiği yükleyecek ve beyaz rengi saydam arkaplan resmi olarak ayarlayacaktır. Bu durumda, sprite'ın boyutları otomatik olarak grafiğin boyutlarına ayarlanacaktır ve boyutları ona aktarmak artık gerekmeyecektir. # Resmin boyutlarına sahip dikdördgen nesneyi # getir # Bu nesnenin yerini rect.x ve rect.y'yi atayarak # güncelle self.rect = self.image.get_rect() rect niteliği Pygame'in sağladığı Rect sınıfının örneği olan bir değişkendir. Dikdördgen, sprite'ın iki boyutunu temsil eder. Bu dikdördgen sınıfı ayarlanabilir olan x ve y için niteliklere sahiptir. Pygame x ve y niteliklerinin olduğu yere sprite'ı çizecektir.Yani bu sprite'ı değiştirmek için programcının mySpriteRef.rect.x ve mySpriteRef.rect.y değerlerini ayarlaması gerekmektedir. Burada mySpriteRef, sprite'ın olduğu değişkene tekabül etmektedir. # Pygame'i başlat pygame.init() # Ekranın yüksekliğini ve genişliğini ayarla screen_width=700 screen_height=400 screen=pygame.display.set_mode([screen_width,screen_height]) Bu kod pygame'i başlatıyor ve pygame için bir pencere oluşturuyor. Burada diğer pygame programlarından farklı yeni bir şey yok. # Bu 'sprite'ların bir listesi. Programdaki her blok # bu listeye ekleniyor. # Bu liste 'Group' denen bir sınıfla yönetiliyor. block_list = pygame.sprite.Group() # Bu her sprite'ın listesi # Bütün bloklar ve oyuncu bloğu da burada. all_sprites_list = pygame.sprite.Group() Spritelar ile çalışmanın büyük bir avantajı listedeki öğelerle çalışma yeteneği. Tüm nesneleri bir çarpışma olup olmadığı konusunda kontrol etmek yerine, program basitçe listedeki tüm nesneleri çarpışmaya karşı kontrol ediyor. Aynı şekilde, sprite gruplarının tamamı konumlarını güncelleyebilir ve basitçe listeye güncellemesi ve çizmesi söylenerek çizilebilir. Bu otomatik olarak listedeki tüm öğeleri güncelleyecek ve çizecektir. Yukarıdaki kod iki liste oluşturuyor. all_sprites_list değişkeni oyundaki her sprite'ı içeriyor. Bu liste tüm spritelar çizilirken kullanılacak. ball_list değişkeni oyuncunun çarpışabileceği her nesneyi tutuyor. Bu örnekte oyuncununki dışında oyundaki her nesneyi içeriyor. Kesin olduğu üzere oyuncu nesnesi, oyuncu nesnesiyle çarpışamaz, sonuç olarak da program oyuncu nesnesinin olmadığı bir listeye ihtiyaç duyar. for i in range(50): # Bu tek bir bloğu temsil ediyor block = Block(black, 20, 15) # Blok için rastgele konum belirleniyor block.rect.x = random.randrange(screen_width) block.rect.y = random.randrange(screen_height) # Bloğu nesnelerin listesine ekliyor block_list.add(block) all_sprites_list.add(block) Bu döngü 46. satırda başlıyor ve 50 adet siyah sprite bloğunu ekrana ekliyor. 48. satır yeni bir blok oluşturuyor; rengini, genişliğini ve yüksekliğini belirliyor. 51 ve 52. satırlar nesnenin görüneceği yerin koordinatlarını ayarlıyor. 55. satır bloğu oyuncunun çarpışabileceği blokların listesine ekliyor. 56. satırda ise bütün blokların olduğu listeye ekliyor. # Kırmızı bir oyuncu bloğu oluştur player = Block(red, 20, 15) all_sprites_list.add(player) 59. satır sonunda oyuncu görevi görecek bir kırmızı blok oluşturuyor. Bu blok çizilebilmesi için all_sprites_list listesine ekleniyor. # Kullanıcı kapatma düğmesine basana kadar döngü done=False # Ekranın ne hızla güncelleneceğini yönetmek için kullanılır clock=pygame.time.Clock() score = 0 # -------- Ana Program Döngüsü ----------- while done==False: for event in pygame.event.get(): # Kullanıcı bir şey yaptı if event.type == pygame.QUIT: # Kullanıcı kapat butonuna bastıysa done=True # Oyunun bittiğini ve döngüden çıkılmasını söyle # Ekranı temizle screen.fill(white) Bu standart program döngüsüdür. 85. satır skoru 0 olarak başlatmaktadır. # Geçerli fare konumunu al. Bu konumu iki sayıdan oluşan # bir liste olarak döndürecektir. pos = pygame.mouse.get_pos() # x ve y değerlerini listeden al, # tıpkı stringden harfleri alırken yaptığımız gibi. # Oyuncu blok nesnesini fare konumuna ayarla player.rect.x=pos[0] player.rect.y=pos[1] 81. satır daha önce tartışılan diğer Pygame programlarına benzer şekilde fare konumunu alıyor. Önemli olan yeni kısım 86-87 numaralı satırlarda sprite'ı içeren dikdördgen yeni bir konuma hareket ettirilirken görülüyor. Bu dikdördgenin 32. satırda oluşturulduğunu ve bu kodun bu satır olmadan çalışmayacağını unutmayın. # Kullanıcı bloğunun herhangi bir şeyle çarpışıp çarpışmadığını kontrol et blocks_hit_list = pygame.sprite.spritecollide(player, block_list, True) Kodun bu satırı player olarak çağırılan sprite'ı alır ve block_list'in içerisindeki tüm bloklara karşı kontrol eder. Bu kod üst üste binen spriteların bir listesini döndürür. Eğer böyle bir sprite yoksa, boş bir liste döndürür. Mantıksal olan True çarpışan spriteları listeden siler. Eğer bu parametre False olarak ayalanırsa spritelar silinmeyecektir. # Çarpışma listesini kontrol et. if len(blocks_hit_list) > 0: score +=len(blocks_hit_list) print( score ) Bu kod, çarpışma listesinde herhangi bir sprite olup olmadığını kontrol eder. Eğer varsa, skoru çarpışılan sprite kadar arttırır. Ardından skoru ekrana yazdırır. 95. satırdaki yazdırma olayının skoru ana pencereye spritelar ile yazdırmadığına, ekran yerine konsola yazdırdığına dikkat edin. # Tüm spriteları çiz all_sprites_list.draw(screen) Bu all_sprites_list içerisindeki tüm spriteların öizilmesine sebep olur. # Saniyede 20 frame (20 FPS) ile sınırla clock.tick(20) # İlerle ve ekranı çizdirdiğimiz son hali ile güncelle pygame.display.flip() pygame.quit() Bu ekranı günceller, ve döngü bittiğinde quit metodunu çağırır. 14.2 Hareket Eden Spritelar Şu ana kadarki örnekte, sadece oyuncu sprite'ı hareket etti. Program tüm spriteların hareket etmesine nasıl sebep olabilir? Bu kolayca yapılabilir, sadece iki aşama gereklidir. İlk aşama Block sınıfına yeni bir metot eklemektir. Bu yeni metot update olarak adlandırılır. Bu update fonksiyonu update metodu çağırıldığında tüm liste için otomatik olarak çağırılacaktır. Şunu sprite'ın içine koyun: def update(self): # Bloğu 1 piksel aşağı oynat self.rect.y += 1 Şunu ana program döngüsüne koyun: # block_list içerisindeki tüm bloklar için update() metodunu çağır block_list.update() Bu kod mükemmel değildir çünkü bloklar ekrandan düşmekte ve tekrar görünmemektedir. Bu kod update fonksiyonunu blokların üstten tekrar görünebilmesi için geliştirecektir. def update(self): # Bloğu bir piksel oynat self.rect.y += 1 if self.rect.y > screen_height: self.rect.y = random.randrange(-100,-10) self.rect.x = random.randrange(0,screen_width) Programın toplanan blokları ekranın üst kısmından sıfırdan bırakması gerekiyorsa, sprite aşağıdaki kod ile değiştirilebilir: def reset_pos(self): self.rect.y = random.randrange(-100,-10) self.rect.x = random.randrange(0,screen_width) def update(self): # Bloğu bir piksel aşağı kaydır self.rect.y += self.change_y if self.rect.y > screen_height: self.reset_pos() self.game.score -= 1 Çarpışma olduğunda blokları yok etmektense, onun yerine program reset_pos fonksiyonunu çağıracak ve blok toplanmaya hazır bir şekilde ekranın üst kısmına gidecektir. # Oyuncu bloğunun bir şeye çarpıp çarpmadığına bak blocks_hit_list = pygame.sprite.spritecollide(player, block_list, True) # Çarpışma listesini kontrol et. if len(blocks_hit_list) > 0: score +=len(blocks_hit_list) print( score ) Yukarıdaki kodu bulun. Blokların yok olmaması için True ifadesini False olarak değiştirin. if ifadesini oyuncunun çarpıştığı her blok için dönecek bir for döngüsüne çevirin. Bu döngüde her blok için block.reset_pos() metodunu çağırın. You are not logged in. Log in here and track your progress. English version by Paul Vincent Craven Russian version by Vladimir Slav Turkish version by Güray Yildirim Dutch version by Frank Waegeman Portuguese version by Tati Carvalho