PyGTK FAQ Snake

Материал из Wiki.crossplatform.ru

(Различия между версиями)
Перейти к: навигация, поиск
(исправил название категории)
(Удалено по требованию автора...)
 
Строка 1: Строка 1:
-
In this part of the PyGTK programming tutorial, we will create a Snake game clone.
 
-
== Snake game ==
 
-
<b>Snake</b> is an older classic video game. It was first created in late 70s. Later it was brought to PCs. In this game the player controls a snake. The objective is to eat as many apples as possible. Each time the snake eats an apple, its body grows. The snake must avoid the walls and its own body. This game is sometimes called <b>Nibbles</b>.
 
-
 
-
== Development ==
 
-
The size of each of the joints of a snake is 10px. The snake is controlled  with the cursor keys. Initially the snake has three joints. The game starts immediately. If the game is finished, we display "Game Over" message in the middle of the Board.
 
-
<source lang="python">
 
-
#!/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()
 
-
</source>
 
-
 
-
First we will define some globals used in our game.
 
-
 
-
The <b>HEIGHT</b> constants determine the size of the Board. The <b>DOT_SIZE</b> is the size of the apple and the dot of the snake. The <b>ALL_DOTS</b> constant defines the maximum number of possible dots on the Board.
 
-
The <b>RAND_POS</b> constant is used to calculate a random position of an apple.
 
-
The <b>DELAY</b> constant determines the speed of the game.
 
-
 
-
<source lang="python">
 
-
x = [0] * ALL_DOTS
 
-
y = [0] * ALL_DOTS
 
-
</source>
 
-
 
-
These two lists store x, y coordinates of all possible joints of a snake.
 
-
 
-
The <b>init_game()</b> method initializes variables, loads images and starts a timeout function.
 
-
 
-
<source lang="python">
 
-
self.left = False
 
-
self.right = True
 
-
self.up = False
 
-
self.down = False
 
-
self.inGame = True
 
-
self.dots = 3
 
-
</source>
 
-
 
-
When the game starts, the snake has three joints. And it is heading to the right.
 
-
 
-
In the <b>move()</b> method we have the key algorithm of the game.
 
-
To understand it, look at how the snakeis moving. You control the head of the snake.
 
-
You can change its direction with the cursor keys. The rest of the joints move one position up the chain. The second joint moves where the first was,  the third joint where the second was etc.
 
-
 
-
<source lang="python">
 
-
while z > 0:
 
-
    x[z] = x[(z - 1)]
 
-
    y[z] = y[(z - 1)]
 
-
    z = z - 1
 
-
</source>
 
-
 
-
This code moves the joints up the chain.
 
-
 
-
<source lang="python">
 
-
if self.left:
 
-
    x[0] -= DOT_SIZE
 
-
</source>
 
-
 
-
Move the head to the left.
 
-
 
-
In the <b>checkCollision()</b> method, we determine if the snake has hit itself or one of the walls.
 
-
 
-
<source lang="python">
 
-
while z > 0:
 
-
    if z > 4 and x[0] == x[z] and y[0] == y[z]:
 
-
        self.inGame = False
 
-
    z = z - 1
 
-
</source>
 
-
 
-
Finish the game, if the snake hits one of its joints with the head.
 
-
 
-
<source lang="python">
 
-
if y[0] > HEIGHT - DOT_SIZE:
 
-
    self.inGame = False
 
-
</source>
 
-
 
-
Finish the game, if the snake hits the bottom of the Board.
 
-
 
-
The <b>locate_apple()</b> method locates an apple randomly  on the form.
 
-
 
-
<source lang="python">
 
-
r = random.randint(0, RAND_POS)
 
-
</source>
 
-
 
-
We get a random number from 0 to RAND_POS - 1.
 
-
 
-
<source lang="python">
 
-
self.apple_x = r * DOT_SIZE
 
-
...
 
-
self.apple_y = r * DOT_SIZE
 
-
</source>
 
-
 
-
These line set the x, y coordinates of the apple object.
 
-
 
-
<source lang="python">
 
-
    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)
 
-
</source>
 
-
 
-
We catch the key press event in the Snake class, and delegate the processing to the board object.
 
-
 
-
In the <b>on_key_dow()</b> method of the Board class, we deternime which keys the player hit.
 
-
 
-
<source lang="python">
 
-
if key == gtk.keysyms.Left and not self.right:
 
-
    self.left = True
 
-
    self.up = False
 
-
    self.down = False
 
-
</source>
 
-
 
-
If we hit the left cursor key, we set <b>self.left</b> variable to  True. This variable is used in the <b>move()</b> method to change coordinates of the snake object. Notice also, that when the snake is heading to the right, we cannot turn immediately to the left.
 
-
 
-
[[image: pygtk_faq_snake.png | center]]
 
-
 
-
This was the Snake computer game programmed using PyGTK programming library.
 
-
 
-
[[Категория:Python]]
 
-
[[Категория:GTK+]]
 

Текущая версия на 11:25, 7 апреля 2009