Python/PyGTK Zetcode/لعبة الثعبان

من PFWiki

اذهب إلى: تصفح, البحث

لعبة الثعبان

فى هذه الجزئية سننشئ نسخة من لعبة الثعبان

نبذة

لعبة الثعبان لعبة فيديو كلاسيكية من اواخر السبعينيات ثم تم استقدامها للحاسب الشخصى، فى هذه اللعبة يتحكم اللاعب فى ثعبان وهدفها هو اكل اكثر عدد ممكن من التفاح، وكلما يأكل الثعبان يكبر حجم جسمه فيجب محاولة تفادى الإصطدام بالحائظ او بجسمه


التطوير

جزء كل قطع الثعبان 10px ويتم التحكم فيه عن طريق الأسهم، ويبدأ الثعبان ب3 قطع وتبدأ اللعبة بالضغط على اى من الأسهم وعند انتهاء اللعبة نعرض Game Over فى منتصف اللوحة


#!/usr/bin/python
 
# ZetCode PyGTK tutorial 
#
# This is a simple snake game
# clone
#
# author: jan bodnar
# website: zetcode.com 
# last edited: February 2009
 
import sys
import gtk
import cairo
import random
import glib
 
 
WIDTH = 300
HEIGHT = 270
DOT_SIZE = 10
ALL_DOTS = WIDTH * HEIGHT / (DOT_SIZE * DOT_SIZE)
RAND_POS = 26
 
x = [0] * ALL_DOTS
y = [0] * ALL_DOTS
 
 
class Board(gtk.DrawingArea):
 
    def __init__(self):
        super(Board, self).__init__()
 
        self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color(0, 0, 0))
        self.set_size_request(WIDTH, HEIGHT)
 
        self.connect("expose-event", self.expose)
 
        self.init_game()
 
    def on_timer(self):
 
        if self.inGame:
            self.check_apple()
            self.check_collision()
            self.move()
            self.queue_draw()
            return True
        else:
            return False
 
    def init_game(self):
 
        self.left = False
        self.right = True
        self.up = False
        self.down = False
        self.inGame = True
        self.dots = 3
 
        for i in range(self.dots):
            x[i] = 50 - i * 10
            y[i] = 50
 
        try:
            self.dot = cairo.ImageSurface.create_from_png("dot.png")
            self.head = cairo.ImageSurface.create_from_png("head.png")
            self.apple = cairo.ImageSurface.create_from_png("apple.png")
        except Exception, e:
            print e.message
            sys.exit(1)
 
        self.locate_apple()
        glib.timeout_add(100, self.on_timer)
 
 
 
 
    def expose(self, widget, event):
 
        cr = widget.window.cairo_create()
 
        if self.inGame:
            cr.set_source_rgb(0, 0, 0)
            cr.paint()
 
            cr.set_source_surface(self.apple, self.apple_x, self.apple_y)
            cr.paint()
 
            for z in range(self.dots):
                if (z == 0): 
                    cr.set_source_surface(self.head, x[z], y[z])
                    cr.paint()
                else:
                    cr.set_source_surface(self.dot, x[z], y[z])                 
                    cr.paint()
        else:
            self.game_over(cr)
 
 
 
    def game_over(self, cr):
 
        w = self.allocation.width / 2
        h = self.allocation.height / 2
 
        (x, y, width, height, dx, dy) = cr.text_extents("Game Over")
 
        cr.set_source_rgb(65535, 65535, 65535)
        cr.move_to(w - width/2, h)
        cr.show_text("Game Over")
        self.inGame = False
 
 
 
    def check_apple(self):
 
        if x[0] == self.apple_x and y[0] == self.apple_y: 
            self.dots = self.dots + 1
            self.locate_apple()
 
 
    def move(self):
 
        z = self.dots
 
        while z > 0:
            x[z] = x[(z - 1)]
            y[z] = y[(z - 1)]
            z = z - 1
 
        if self.left:
            x[0] -= DOT_SIZE
 
        if self.right: 
            x[0] += DOT_SIZE
 
        if self.up:
            y[0] -= DOT_SIZE
 
        if self.down:
            y[0] += DOT_SIZE
 
 
 
    def check_collision(self):
 
        z = self.dots
 
        while z > 0:
            if z > 4 and x[0] == x[z] and y[0] == y[z]:
                self.inGame = False
            z = z - 1
 
        if y[0] > HEIGHT - DOT_SIZE: 
            self.inGame = False
 
        if y[0] < 0:
            self.inGame = False
 
        if x[0] > WIDTH - DOT_SIZE:
            self.inGame = False
 
        if x[0] < 0:
            self.inGame = False
 
 
    def locate_apple(self):
 
        r = random.randint(0, RAND_POS)
        self.apple_x = r * DOT_SIZE
        r = random.randint(0, RAND_POS)
        self.apple_y = r * DOT_SIZE
 
 
    def on_key_down(self, event): 
 
        key = event.keyval
 
        if key == gtk.keysyms.Left and not self.right: 
            self.left = True
            self.up = False
            self.down = False
 
 
        if key == gtk.keysyms.Right and not self.left:
            self.right = True
            self.up = False
            self.down = False
 
 
        if key == gtk.keysyms.Up and not self.down:
            self.up = True
            self.right = False
            self.left = False
 
 
        if key == gtk.keysyms.Down and not self.up: 
            self.down = True
            self.right = False
            self.left = False
 
 
class Snake(gtk.Window):
 
    def __init__(self):
        super(Snake, self).__init__()
 
        self.set_title('Snake')
        self.set_size_request(WIDTH, HEIGHT)
        self.set_resizable(False)
        self.set_position(gtk.WIN_POS_CENTER)
 
        self.board = Board()
        self.connect("key-press-event", self.on_key_down)
        self.add(self.board)
 
        self.connect("destroy", gtk.main_quit)
        self.show_all()
 
 
    def on_key_down(self, widget, event): 
 
        key = event.keyval
        self.board.on_key_down(event)
 
 
Snake()
gtk.main()

اولا، نعرف الثوابت فى اللعبة.

WIDTH, HEIGHT ثوابت العرض والإرتفاع لتحديد مساحة اللوحة

DOT_SIZE لتحديد حجم التفاحة (النقط)

ALL_DOTS اكبر عدد ممكن من النقط

RAND_POS ثابت يحسب موقع عشوائى للتفاحة

DELAY ثابت يحدد سرعة اللعبة


 x = [0] * ALL_DOTS
 y = [0] * ALL_DOTS

المصفوفتين يخزنو كل احداثيات ال x, y لمكونات الثعبان

الطريقة init_game .. تنشئ المتغيرات وتحمل الصور وتبدأ دالة ال timeout


These two lists store x, y coordinates of all possible joints of a snake.

The init_game() method initializes variables, loads images and starts a timeout function.

 self.left = False
 self.right = True
 self.up = False
 self.down = False
 self.inGame = True
 self.dots = 3

فى بداية اللعبة، الثعبان لديه 3 قطع ورأسه لليمين

When the game starts, the snake has three joints. And it is heading to the right.

الطريقة Move، فيها نستخدم الأسهم للتحكم فى اتجاه حركة الثعبان (بإستخدام القطعة الأولى للثعبان) ثم يليها القطع الباقية


 while z > 0:
     x[z] = x[(z - 1)]
     y[z] = y[(z - 1)]
     z = z - 1


هذا الكود يحرك المكونات فى سلسلة

 if self.left:
     x[0] -= DOT_SIZE


يحرك الرأس لليسار

فى الطريقة checkCollision نختبر عملية التصادم (سواء بنفسه او بالحوائط)

 while z > 0:
     if z > 4 and x[0] == x[z] and y[0] == y[z]:
         self.inGame = False
     z = z - 1


ننهى اللعبة فى حال اصطدام الرأس بأى من مكونات الجسم

 if y[0] > HEIGHT - DOT_SIZE: 
     self.inGame = False

ننهى اللعبة اذا اصطدم الثعبان بأسفل اللوحة

The locate_apple() method locates an apple randomly on the form.

 r = random.randint(0, RAND_POS)

نحصل على رقم عشوائى من 0 الى RAND_POS - 1


 self.apple_x = r * DOT_SIZE
 ...
 self.apple_y = r * DOT_SIZE


تحدد احداثيات ال س ، ص للتفاحة

    self.connect("key-press-event", self.on_key_down)
     ...
 
 def on_key_down(self, widget, event): 
 
     key = event.keyval
     self.board.on_key_down(event)


نصطاد الضغة على اى من المفاتيح ونعالجها فى on_key_down التابعة للصف Board لنحدد اى مفتاح ضغطه اللاعب

We catch the key press event in the Snake class, and delegate the processing to the board object.

 if key == gtk.keysyms.Left and not self.right: 
     self.left = True
     self.up = False
     self.down = False

اذا ضغطنا على سهم يسار ، نقوم بإسناد قيمة True للمتغير self.left المستخدم فى الطريقة move لنغير احداثات الثعبان، لاحظ ايضا عندما يكون الثعبان متجه لليمين لانستطيع تحويله مباشرة لليسار


snake.png

هذه كانت لعبة الثعبان، تم كتابتها ب PyGTK

أدوات شخصية