贪吃蛇游戏升级版本

# 贪吃蛇游戏介绍:

# 初始速度为400ms运动一步,当蛇身长度超过35节时,判定通关,

# 定时器时间减少20毫秒(运动速度加快),当定时器时间小于200毫秒时,

# 运动速度不再加快。如果你的显卡性能较好,可以尝试降低200毫秒的下线。



# 贪吃蛇游戏源码

gui = GUI("fine")

#gui.HideConsoleWindow()

time = TIME()

math = MATH()


GAME_WIDTH  = 384

GAME_HEIGHT = 288


# 初始化方向

global direction = "right"          # 初始运动方向向右

global Snake

global head_x

global head_y


# 自定义类

class SNAKE(object)                # object 不能省略,object表示是基类,可以继承

{

    snake = []

    food  = []

    def draw(self,gui)       # draw方法是刷新界面,参数1是类对象本身,参数2是窗口ID

    {

        packageList = []     # 先创建一个空的指令包

        # 首先刷新游戏背景

        drawlist = ["CanvasPutImage","background",0,0,384,288]     # 重画背景指令

        packageList.append(drawlist)                       # 把指令打包

        # 刷新食物

        listfood = self.food       # 获取食物属性。listfood[0],listfood[1]是食物位置,listfood[2]是食物图片昵称

        drawlist = ["PutImage",listfood[2],listfood[0],listfood[1],32,32] 

        packageList.append(drawlist)


        # 刷新蛇

        listsnake = self.snake          # 获取设身体属性 

        for tp in listsnake            # len(listsnake)是蛇的长度

        {

            # ti[0]~tp[1]是蛇的部件的位置,tp[2]是蛇的部位昵称,tp[3]是蛇的运动方向

            drawlist = ["PutImage",tp[2],tp[0],tp[1],16,16]     # 循环获取蛇身的每一段位置

            packageList.append(drawlist)                        # 打包

        }

        gui.DrawPackage(packageList)        # 一次性发出剩余画指令

    }

}


# 移动蛇

def move_snake(Snake)    # 参数是个全局变量,是蛇对象

{

    delt_x = 0

    delt_y = 0

    

    snake_list = Snake.snake     # 取出蛇身体是个双重列表:[[x0,y0,"Head","方向"],[x1,y1,"Body","方向"],……]

    Snake_Head = snake_list[0]   # 蛇头列表

    head_x = Snake_Head[0]       # 蛇头x位置    

    head_y = Snake_Head[1]       # 蛇头y位置


    if direction == "right"

    {

        delt_x = 16     # 一次移动8个像素

    }

    elif direction == "left"

    {

       delt_x =  - 16

    }

    elif direction == "up"

    {

        delt_y = - 16

    }

    elif direction == "down"

    {

        delt_y =  16

    }


    # 边界检测

    head_x = head_x + delt_x     #

    head_y = head_y + delt_y     #

    if (head_x < 0) or (head_x > GAME_WIDTH) or (head_y < 0) or (head_y > GAME_HEIGHT) 

    {

        return False

    }


  

    # 将当前蛇头一节用蛇身节替换

    Snake_Head.replace(2,"Body")              # Snake_Head的第二项是皮肤,给蛇头换皮肤

    snake_list.replace(0,Snake_Head)          # 组合换装后的蛇,蛇头已经被蛇身替换

    

    head = [head_x,head_y,"Head",direction]   # 构造新的蛇头

    snake_list.insert(0,head)                 # 给蛇增加一个蛇头(不论是否吃到食物,先增加一个节蛇身)


    # 获取当前食物位置

    food_list = Snake.food

    food_x = food_list[0]

    food_y = food_list[1]


    # 判断是否吃到食物

    if head_x > food_x-20 and head_x < food_x+20 and head_y > food_y-20 and  head_y < food_y+20    

    {   

        # 如果吃到食物,蛇身维持新的状态,同时,重新随机放置食物

        food_x = math.rand(32,GAME_WIDTH-32)-8

        food_y = math.rand(32,GAME_HEIGHT-32)-8

        food_list = [food_x,food_y,"Food"]       # 参数1~2是位置,参数3食物

    }

    else  # 没有吃到食物,恢复蛇身体,并前进一步

    {

        x = snake_list.pop()                 # 先抛弃掉最后一节

        length = len(snake_list)             # 计算当前蛇身长度

        temp_list = snake_list[length-2]     # 取出蛇身倒数第二节 temp_list = [xn-2,yn-2,"Body","方向"]

        temp_list.replace(2,"Tail1")         # 将倒数第二节的图形换掉 temp_list = [xn-2,yn-2,"Tail1","方向"]

        temp_list = snake_list[length-1]     # 取出蛇身倒数第二节 temp_list = [xn-1,yn-1,"Body","方向"]

        temp_list.replace(2,"Tail0")         # 将倒数第二节的图形换掉 temp_list = [xn-1,yn-1,"Tail0","方向"]

        # 这样做始终保持尾部是小图形

    }

    # 由于类属性发生了变化,生成新的贪吃蛇类对象

    Snake = SNAKE(snake_list,food_list)      # 根据更新后的数据,生成新的贪吃蛇的类对象

    return True

}


# 定义初始化函数

def init()

{

    # 初始化,食物随机位置

    food_x = math.rand(32,GAME_WIDTH-32)-8     # 食物坐标

    food_y = math.rand(32,GAME_HEIGHT-32)-8    # 食物坐标

    food_list = [food_x,food_y,"Food"]         # 食物列表:参数1~2是位置,参数3食物图片名称

    # 初始化蛇体,只有三节

    snake_list0 = [3*16,5*16,"Head" ,"right"]            # 参数1~2是位置,参数3是体态,惨数4是方向

    snake_list1 = [2*16,5*16,"Tail1","right"]

    snake_list2 = [1*16,5*16,"Tail0","right"]

    snake_list = [snake_list0,snake_list1,snake_list2]   # snake_list是双重列表,是蛇身体,包含三节。

    direction = "right"      # 初始运动方向向右

    # 生成初始化类对象

    Snake = SNAKE(snake_list,food_list)   # 生成贪吃蛇的类对象

}


# 创建游戏窗口

title       = "贪吃蛇游戏"                          # 窗口标题

size        = [10,3,52,25]                        # 窗口尺寸

# 四个方向控制按钮

button_up    = ["上", "button", 5, 20.5, 8, 1,"VK_UP"]      #"VK_UP"代表向上箭头的按键

button_down  = ["下", "button", 17, 20.5, 8, 1,"VK_DOWN"]    #"VK_DOWN"代表向下箭头的按键

button_left  = ["左", "button", 29, 20.5, 8, 1,"VK_LEFT"]    #"VK_LEFT"代表向左箭头的按键

button_right = ["右", "button", 41, 20.5, 8, 1,"VK_RIGHT"]   #"VK_RIGHT"代表向右箭头的按键


list = [title,size,button_up,button_down,button_left,button_right]    # 打包窗口元素

gui.Fine(list)                                                        # 创建Fine窗口,并返回资源ID

# 加载游戏资源

loadList = []     # 创建一个空的列表,用于打包绘图指令


drawlist = ["LoadImage","C:\\fine\\fin\\examples\\snake\\background.bmp","background"]     # 加载背景图片

loadList.append(drawlist)                                                                  # 添加到指令包


drawlist = ["LoadImage","C:\\fine\\fin\\examples\\snake\\food.bmp","Food"]                 # 加载食物图片

loadList.append(drawlist)


drawlist = ["LoadImage","C:\\fine\\fin\\examples\\snake\\snakeBody.bmp","Body"]            # 加载身体图片

loadList.append(drawlist)


drawlist = ["LoadImage","C:\\fine\\fin\\examples\\snake\\snakeHead.bmp","Head"]            # 加载头图片

loadList.append(drawlist)


drawlist = ["LoadImage","C:\\fine\\fin\\examples\\snake\\snakeTail1.bmp","Tail1"]          # 加载尾部大图片

loadList.append(drawlist)


drawlist = ["LoadImage","C:\\fine\\fin\\examples\\snake\\snakeTail0.bmp","Tail0"]          # 加载尾部小图片

loadList.append(drawlist)


# gui.DrawPackageDone()返回True表示DrawPackage指令忙,需等待其返回False,方可执行DrawPackage指令

while gui.DrawPackageDone() {continue}  # gui.DrawPackageDone()返回False退出循环

gui.DrawPackage(loadList)                 # 一次性加载所有资源


init()             # 初始化SNAKE

speed = 400        # 初始速度400ms,数字越小速度越快,太小会导致系统处理不过来

num = time.SetTimer(speed)


while gui.FineClosed() != -1     # 检查窗口关闭消息

{

    PowerDown(3) 

    if gui.FineReady() == 0      # 有按键按下

    {

        x = gui.FineRead()

        button_action = x[0]

        if button_action == "button-0"    # 上

        {

            direction = "up"

        }

        elif button_action == "button-1"  # 下

        {

            direction = "down"

        }

        elif button_action == "button-2"  # 左

        {

            direction = "left"

        }

        elif button_action == "button-3"  # 右

        {

            direction = "right"

        }  

        buttonenable = 0     # 禁止按键,避免多次按键

    }  

     

    # 检测定时器是否溢出,如果返回True,说明定时器溢出,注销定时器 

    if not time.TestTimer(num) {continue}


    if not move_snake(Snake)             # 按既定方向移动一位,如果越界game over,没有越界继续

    {

        time.KillTimer(num)

        box = GUI("box")

        box.MessageBox("游戏结束!是否继续?","确定|取消")

        while box.MessageBoxClosed() != -1 {PowerDown(3)}

        select  = box.MessageBoxRead()

        if select != 0

        {

             gui.CloseFine()              # 关闭窗口,退出程序

             break

        }

        else                              # 如果按了确定键

        {

            init()                        # 初始化

            num = time.SetTimer(speed)    # 重新设置定时器

            continue                     # 跳转到while循环起点

        }

    }


    if len(Snake.snake) > 35           # 如果蛇身体长大到超过10节,认为可以通关了。

    {

        time.KillTimer(num)

        box = GUI("box")

        box.MessageBox("恭喜你顺利通关!再来一局?","确定|取消")

        while box.MessageBoxClosed() != -1 {PowerDown(3)}

        x  = box.MessageBoxRead()

        if x == 0                          # 如果选择继续玩,则逐渐提高速度

        {

            speed = speed - 20             # 速度逐渐变快

            if speed < 200

            {

                speed = 200                 # 限制最快速度

            }

            init()                         # 初始化

            num = time.SetTimer(speed)     # 重新设置定时器

            continue                      # 重启游戏

        }

        else                              # 如果选择取消、或直接关闭MessageBox窗口,则退出程序

        {

            gui.CloseFine()                # 关闭窗口,退出程序

            break

        }

    }

    

    # 由于Snake的方法Snake.draw(gui)调用了gui.DrawPackage指令,

    # 因此,需事先检测DrawPackage指令是否处于空闲状态,只有空闲状态,方可调用gui.DrawPackage()

    while gui.DrawPackageDone() {continue}    # 如果gui.DrawPackageDone()返回True,表示忙,需等待

    Snake.draw(gui)                            # 当gui.DrawPackageDone()返回False时,执行绘图

    num = time.SetTimer(speed)                 # 重新设置定时器

}

0