[翻译]Ruby GTK教程8——贪吃蛇

贪吃蛇

在这部分的Ruby GTK编程教程中我们将创建一个贪吃蛇游戏。


贪吃蛇是一个比较老的经典电子游戏。它第一次创建是在70年代后期。之后被移植到PC上。在这个游戏中玩家控制蛇,目标是尽可能多的吃掉苹果。蛇每吃掉一个苹果,身体就会变长。必须避免蛇撞到墙或者自己的身体。


开发


蛇的每块关节的大小为10像素。使用方向键控制蛇。初始,蛇有三块关节。游戏立即开始。当游戏结束后在窗口中央显示”Game Over”。


board.rb


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 initialize
super

modify_bg Gtk::STATE_NORMAL, Gdk::Color.new(0, 0, 0)

signal_connect “expose-event” do
on_expose
end

init_game
end

def on_timer

if @inGame
check_apple
check_collision
move
queue_draw
return true
else
return false
end
end

def init_game

@left = false
@right = true
@up = false
@down = false
@inGame = true
@dots = 3

for i in (0..@dots)
$x[i] = 50 - i 10
$y[i] = 50
end

begin
@dot = Cairo::ImageSurface.from_png “dot.png”
@head = Cairo::ImageSurface.from_png “head.png”
@apple = Cairo::ImageSurface.from_png “apple.png”
rescue Exception => e
puts “cannot load images”
exit
end

locate_apple
GLib::Timeout.add(100) { on_timer }

end


def on_expose

cr = window.create_cairo_context

if @inGame
draw_objects cr
else
game_over cr
end
end

def draw_objects cr

cr.set_source_rgb 0, 0, 0
cr.paint

cr.set_source @apple, @apple_x, @apple_y
cr.paint

for z in (0..@dots)
if z == 0
cr.set_source @head, $x[z], $y[z]
cr.paint
else
cr.set_source @dot, $x[z], $y[z]
cr.paint
end
end
end

def game_over cr

w = allocation.width / 2
h = allocation.height / 2

cr.set_font_size 15
te = cr.text_extents “Game Over”

cr.set_source_rgb 65535, 65535, 65535

cr.move_to w - te.width/2, h
cr.show_text “Game Over”

end


def check_apple

if $x[0] == @apple_x and $y[0] == @apple_y
@dots = @dots + 1
locate_apple
end
end

def move

z = @dots

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

if @left
$x[0] -= DOT_SIZE
end

if @right
$x[0] += DOT_SIZE
end

if @up
$y[0] -= DOT_SIZE
end

if @down
$y[0] += DOT_SIZE
end

end

def check_collision

z = @dots

while z > 0
if z > 4 and $x[0] == $x[z] and $y[0] == $y[z]
@inGame = false
end
z = z - 1
end

if $y[0] > HEIGHT - DOT_SIZE
@inGame = false
end

if $y[0] < 0
@inGame = false
end

if $x[0] > WIDTH - DOT_SIZE
@inGame = false
end

if $x[0] < 0
@inGame = false
end

end

def locate_apple

r = rand(RAND_POS)
@apple_x = r
DOT_SIZE
r = rand(RAND_POS)
@apple_y = r DOT_SIZE
end

def on_key_down event

key = event.keyval

if key == Gdk::Keyval::GDK_Left and not @right
@left = true
@up = false
@down = false
end

if key == Gdk::Keyval::GDK_Right and not @left
@right = true
@up = false
@down = false
end

if key == Gdk::Keyval::GDK_Up and not @down
@up = true
@right = false
@left = false
end

if key == Gdk::Keyval::GDK_Down and not @up
@down = true
@right = false
@left = false
end
end
end

首先我们定义一些全局变量。


WIDTH和HEIGHT常量决定了甲板的大小。DOT_SIZE是苹果和蛇的每个点的大小。ALL_DOTS常量定义了甲板可能包含的最大的点数量。RAND_POS常量用于计算苹果的随机位置。DELAY常量决定游戏速度。


$x = [0]  ALL_DOTS
$y = [0] ALL_DOTS

这两个数组存储了蛇所有关节的x、y坐标。


init_game方法初始化变量、加载图片和启动timeout函数。


if @inGame
draw_objects cr
else
game_over cr
end

on_expose_method方法里我们检查@inGame变量。如果为true,绘制苹果和蛇。否则显示”Game over”文字。


def draw_objects cr

cr.set_source_rgb 0, 0, 0
cr.paint

cr.set_source @apple, @apple_x, @apple_y
cr.paint

for z in (0..@dots)
if z == 0
cr.set_source @head, $x[z], $y[z]
cr.paint
else
cr.set_source @dot, $x[z], $y[z]
cr.paint
end
end
end

draw_objects方法绘制苹果和蛇。蛇的头部用红色的圆表示。


def check_apple

if $x[0] == @apple_x and $y[0] == @apple_y
@dots = @dots + 1
locate_apple
end
end

check_apple方法查检蛇是否碰到苹果,如果是则增加蛇的关节并调用locate_apple方法随机放置一个新的苹果。


move方法是游戏的关键算法。为了理解它,先看一下蛇是如何移动的。控制蛇头,可以使用方向键改变它的方向。其余的关节朝该方向前进。第二个关节移到到第一关节的位置,第三个关节到第二个等等。


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

这些代码将关节按照链状前进。


if @left
$x[0] -= DOT_SIZE
end

头部向左移动。


check_collision方法中,我们检查蛇是否撞到了自己或者墙。


while z > 0
if z > 4 and $x[0] == $x[z] and $y[0] == $y[z]
@inGame = false
end
z = z - 1
end

如果蛇撞到了自己,游戏结束。


if $y[0] > HEIGHT - DOT_SIZE
@inGame = false
end

如果蛇撞到底部,游戏结束。


localte_apple方法在甲板上随机定位一个苹果。


r = rand(RAND_POS)

获取0到RAND_POS-1的一个随机数。


@apple_x = r  DOT_SIZE

@apple_y = r * DOT_SIZE

这几行设置了苹果的x、y坐标。


if @inGame
check_apple
check_collision
move
queue_draw
return true
else
return false
end

第140ms调用一次on_timer方法。如果游戏运行则调用三个组成游戏逻辑的方法。否则返回false,停止定时事件。


在Board类的on_key_down方法中我们判断按下的键。


if key == Gdk::Keyval::GDK_Left and not @right
@left = true
@up = false
@down = false
end

如果我们按的是左方向键,我们设置left变量为true。这个变量用于move方法改变蛇的坐标。同样注意,当蛇是朝右时,我们不能立即朝左。


nibbles.rb


#!/usr/bin/ruby

# ZetCode Ruby GTK tutorial
#
# This is a simple nibbles game
# clone
#
# author: jan bodnar
# website: www.zetcode.com
# last modified: June 2009

require ‘gtk2’
require ‘board’

class RubyApp > Gtk::Window
def initialize
super

set_title “Nibbles”
signal_connect “destroy” do
Gtk.main_quit
end

@board = Board.new
signal_connect “key-press-event” do |w, e|
on_key_down(w, e)
end

add @board

set_default_size 300, 270
set_window_position Gtk::Window::POS_CENTER
show_all
end

def on_key_down widget, event

key = event.keyval
@board.on_key_down event
end
end

Gtk.init
window = RubyApp.new
Gtk.main

在这个类我们启动了贪吃游戏。


def on_key_down widget, event

key = event.keyval
@board.on_key_down event
end

在这个类的捕获按键事件然后委托Board类的on_key_down method方法进行处理。


image

图片:贪吃蛇


这是使用Ruby语言和GTK库编写的贪吃蛇计算机游戏。




原文地址: http://zetcode.com/gui/rubygtk/nibbles/

翻译:龙昌 admin@longchangjin.cn