Python編程娃娃源代碼

"""bcwawa.py

   《編程娃娃Python版》是繼《編程娃娃》的姊妹篇。它不需要拖曳編程命令,採用的是直接編排圖形化指令的模式,指揮一個娃娃回家。

   此版本更重要的是能做爲一個模塊導入到Python原生環境,從而實現用真正的Python命令去指揮娃娃移動。

   本版本新增命令如下:

   forward:前進50像素,縮寫爲:fd,使用方法: fd()

   backward:倒退50,縮寫爲:bk,back,使用方法:bk()

   right:右轉90,縮寫:rt, 使用方法:rt()

   left:左轉90,縮寫:lt,使用方法:lt()

   jump:前進100,主要用來跳過炸彈。使用方法:jump()

   bomb_ahead:檢測娃娃前面是否有炸彈,返回布爾值。使用方法: bomb_ahead()

   playmusic:播放音樂,不輸入參數會播放小星星曲子。使用方法: playmusic()

   pausemusic:暫停播放音樂。使用方法: playmusic()

   stopmusic:停止播放音樂。使用方法: stopmusic()

   unpausemusic:繼續播放音樂。使用方法: unpausemusic()

   set_level:設置當前關卡號。使用方法: set_level(3)

   娃娃根據指令前進的主要原理如下:
   在作品中設計了三排按鈕,娃娃能訪問這三排按鈕。
   第一排是子指令表1(相當於子程序1),以橙星開始,後面跟着9個指令按鈕。
   第二排也是子指令表2(相當於子程序2),以綠星開始,後面跟着9個指令按鈕。
   第三排代表主指令表(相當於主程序),以信封開始,後面跟着9個指令按鈕.
   程序啓動後,娃娃對象生成,它會註冊回車鍵綁定自己的execute方法。
   當按回車鍵或單擊信封按鈕時,娃娃就像是收到了信的內容,會根據信的內容執行它的execute方法。
   這個方法執行時會遍歷主指令列表,從而根據主指令表中的命令讓娃娃前進,轉向或執行子指令表。
   子程序也能調用子程序,但不能調用主程序。當子程序遞歸調用過多時,娃娃會自動停止移動。
 
   讓娃娃移動的三種方法:
   
   1、按鍵:直接按上、下、左、右,空格鍵,手動操作娃娃。適合於體驗按鍵。

   2、編排圖形化指令:單擊信封及五角星後面的按鈕,給娃娃編排指令。信封后面的9個按鈕爲主指令表,橙星爲調用子程序1指令,綠星爲調用子程序2指令。   

      向上箭頭爲前進指令(並不僅僅是向上移動,而是朝它當前的方向移動)。向右轉箭頭爲右轉指令,向左轉箭頭爲左轉指令,彎箭頭爲跳躍指令。

   3、Python編程模式:把本程序做爲模塊導入,然後通過編寫Python代碼指揮娃娃前進。典型代碼舉例:

      from bcwawa import *    
      set_level(9)            # 設置當前關卡爲第9關。
      sleep(3)
      for i in range(4):      # 這個for循環的意思是重複4次“前進前進右轉”
          fd();fd()
          rt()

   配置文件名:cfg.txt
   本程序的房子和炸彈這兩種道具擺放方式分爲過關模式與隨機模式。過關模式是按內置的排列順序每關擺放在固定的位置。
   隨機模式每個關卡都是隨機的。
   如果配置文件不存在,則默認爲過關模式。
   如果配置文件存在,裏面的字符串爲1,則也是關卡模式,其它字符則爲隨機擺放模式。
   主要原理:在生成娃娃對象時,傳遞__game_mode__變量的值,讓娃娃知道模式,當它碰到房子就能決定採用哪種方式重新擺放道具。
   
   

"""
__author__ = "李興球"
__date__ = "2018/10"
__email__ = "[email protected]"
__version__ = "1.0"

import sys,os,webbrowser
from turtle import *
from codewawa.gridturtle import *
from codewawa.bomb import *
from codewawa.house import *
from codewawa.wawa import *
from codewawa.command import *
from random import randint
from time import sleep

"全局變量加雙下劃線,不污染全局名稱空間"
__gamename__ = "編程娃娃Python版"
__images_folder__ = os.getcwd() + os.sep + "images" + os.sep
__audios_folder__ = os.getcwd() + os.sep + "audios" + os.sep
__explosion_sound__=__crystalsound__=__stepsound__=__rotatesound__=__jumpsound__ = None
__sounds__ = [ ]                                     # 娃娃的三個音效表
__pygame_normal__ = True                             # 描述pygame是否正常或能否初始化混音器
__wawagif__ = []                                     # 娃娃的4個方向gif圖片表
__commandpic__= []                                   # 命令按鈕gif圖片表
__screen_width__,__screen_height__ = 660,660         # 設定屏幕寬度和高度
__explode_image_list__ = []                          # 爆炸效果造型表
__house_list__ = []                                  # 多個圖片只是爲了房子有動態效果
__mute_list__ = []
__all_images__ = ['invalid.gif', 'roundman_down.gif', 'roundman_left.gif', 'roundman_right.gif', 'roundman_up.gif', 'volumeOff.gif', 'volumeOn.gif', '信封.gif', '前進.gif', '右轉.gif', '左轉.gif', '房子0.gif', '房子1.gif', '橙星.gif', '橙色星.gif', '炸彈.gif', '爆炸效果-0.gif', '爆炸效果-1.gif', '爆炸效果-10.gif', '爆炸效果-11.gif', '爆炸效果-2.gif', '爆炸效果-3.gif', '爆炸效果-4.gif', '爆炸效果-5.gif', '爆炸效果-6.gif', '爆炸效果-7.gif', '爆炸效果-8.gif', '爆炸效果-9.gif', '綠星.gif', '綠色星.gif', '跳躍.gif']
__all_images__ = [ __images_folder__ + image for image in __all_images__]
__download_url__ = "http://www.scratch8.net/downloads/bcwawa_python.rar"

def check_images():
    """圖像文件丟失檢測,在主程序所在文件夾下面要有名爲images目錄名的文件夾,存儲圖像資源。"""
    for image in __all_images__:
        if not os.path.exists(image):
            info = image + "文件丟失。"
            info = info + "請從以下網址重新下載本軟件:" + "\n"
            info = info  + __download_url__            
            showerror(__gamename__,info)
            
            return False
    return True


def __load_cfg__(filename):
    """加載配置文件"""
    if os.path.exists(filename):   # 配置文件存在則讀取字符串
        f = open(filename)
        __game_mode__ = f.read()
        f.close()
        if __game_mode__.strip() == "1":# 字符串爲1,關卡模式爲過關模式
            __game_mode__ = 1
        else:
            __game_mode__ = 0           # 爲其它字符串爲隨機擺放模式
    else:
        __game_mode__ = 1               # 文件不存在,默認爲關卡模式
    return __game_mode__


    
def __init_screen__(width,height,bgcolor,title):
    """初始化屏幕,註冊gif圖到形狀列表"""
 
    __wawagif__.append(__images_folder__ + "roundman_right.gif")  # 娃娃朝向右的圖形
    __wawagif__.append(__images_folder__ + "roundman_up.gif")     # 娃娃朝向上的圖形
    __wawagif__.append(__images_folder__ + "roundman_left.gif")   # 娃娃朝向左的圖形
    __wawagif__.append(__images_folder__ + "roundman_down.gif")   # 娃娃朝向下的圖形

    __commandpic__.append(__images_folder__ + "前進.gif")    # “前進”指令的圖形
    __commandpic__.append(__images_folder__ + "左轉.gif")    # “左轉” 指令的圖形
    __commandpic__.append(__images_folder__ + "右轉.gif")    # “右轉”指令的圖形
    __commandpic__.append(__images_folder__ + "橙星.gif")    # “子程序1”指令的圖形
    __commandpic__.append(__images_folder__ + "綠星.gif")    # “子程序2”指令的圖形
    __commandpic__.append(__images_folder__ + "跳躍.gif")    # “跳躍”指令的圖形
    __commandpic__.append(__images_folder__ + "invalid.gif") #  “無”指令的圖形

    __explode_image_list__ .append( __images_folder__ + "炸彈.gif")                         # 定義爆炸造型表
    __explode_image_list__.extend([ __images_folder__ + "爆炸效果-" + str(i) + ".gif" for i in range(12)])

    __house_list__.append(__images_folder__ + "房子0.gif")
    __house_list__.append(__images_folder__ + "房子1.gif")

    __mute_list__.append(__images_folder__ + "volumeOn.gif")
    __mute_list__.append(__images_folder__ + "volumeOff.gif")
    
    screen = Screen()
    screen.title(title)
    screen.bgcolor(bgcolor)
    screen.setup(width,height)
    screen.delay(0)
    if not check_images():screen.bye();return
      
    [screen.addshape(image) for image in __commandpic__]  # 註冊所有命令按鈕的造型到屏幕
    [screen.addshape(image) for image in __wawagif__]     # 註冊所有娃娃的造型到屏幕的形狀列表
    [screen.addshape(image) for image in __explode_image_list__]  # 註冊炸彈的所有造型到形狀列表    
    [screen.addshape(image) for image in __house_list__]   # 註冊房子的造型到形狀列表
    [screen.addshape(image) for image in __mute_list__]   # 註冊靜音按鈕的造型到形狀列表        
    
    return screen

def __draw_grid__(start,end,rowscols):
    """畫格子的函數,參數說明:
    start:起始座標元組,左上角
    end:結束座標元組,  右下角
    rowscols:行和列數
    """
    g = Gridturtle()                        # 畫格子的海龜對象   
    g.drawgrid(start,end,rowscols,"gray",4) # 格子海龜專業畫格子

def __make_button__():
    """生成命令按鈕,每個按鈕有7種指令,對應7張gif圖,它們都在列表中。
       單擊按鈕會調用相應的方法切換指令,同時切換到相應的圖形。

    """
    suborange = []    # 子程序1指令序列
    for x in range(-200,201,50):
        suborange.append(Command(__commandpic__,__commandlist__,x,-100))
        
    subgreen = []     # 子程序2指令序列
    for x in range(-200,201,50):
        subgreen.append(Command(__commandpic__,__commandlist__,x,-150))
        
    main = []         # 主程序指令序列
    for x in range(-200,201,50):
        main.append(Command(__commandpic__,__commandlist__,x,-200))
        
    return suborange,subgreen,main
 
         
def forward():
    """讓娃娃前進50個像素"""
    wawa.fd50()
def right():
    """讓娃娃右轉90度"""
    wawa.rt90()
def left():
    """讓娃娃左轉90度"""
    wawa.lt90()
def jump():
    """讓娃娃跳過一格,實際上是前進100個像素"""
    wawa.jump()
def backward():
    """讓娃娃倒退50個像素"""
    wawa.fd_50()



def bomb_ahead():
    """檢測在娃娃的前進方向上是否有一個炸彈"""
    return wawa.front_have_bomb_check()


def playmusic(filename = __audios_folder__ + "小星星.wav",times = -1):
    """播放音樂,times:播放次數,-1表示無限,0表示1次,1表示播放1次,2表示播放3次,詳情看pygame說明書"""
    try:
        pygame.mixer.music.load( filename)
        pygame.mixer.music.play(times,0)
    except:
        print("出錯了,音樂文件不存在或無法播放。")
        
    
def stopmusic():
    """停止播放音樂"""
    try:
        pygame.mixer.music.stop()
    except:
        pass   
def pausemusic():
    """暫停播放音樂"""
    try:
        pygame.mixer.music.pause()
    except:
        pass   
def unpausemusic():
    """繼續播放音樂"""
    try:
        pygame.mixer.music.unpause()
    except:
        pass
    
def __init_audio__():
    """本函數試圖導入pygame模塊,如果導入不成功或者混音初
    始化不成功,相關變量的值都爲None,程序仍舊能運行,只是不發聲。
    """
    global __pygame_normal__,__explosion_sound__,__crystalsound__,__stepsound__,__rotatesound__,__jumpsound__
    try:
        import pygame
        pygame.mixer.init()  
    except:
        pygame = None
        __pygame_normal__ = False
        print("pygame模塊沒有安裝或混音器初始化不成功。請重新安裝pygame模塊。\n安裝方法,請在命令提示符下輸入:pip install pygame --user。")

    if __pygame_normal__:                   # 如果pygame正常
        try:
            __explosion_sound__ = pygame.mixer.Sound( __audios_folder__ + "BOMB2.wav")
            __crystalsound__ = pygame.mixer.Sound( __audios_folder__ + "水晶.wav")
            __stepsound__ = pygame.mixer.Sound( __audios_folder__ + "步進聲.wav")
            __rotatesound__ = pygame.mixer.Sound( __audios_folder__ + "轉彎聲.wav")
            __jumpsound__ = pygame.mixer.Sound( __audios_folder__ + "跳躍聲.wav")
        except:
            pass         
        __sounds__.append(__stepsound__)
        __sounds__.append(__rotatesound__)
        __sounds__.append(__jumpsound__)
    return pygame

def set_level(number = 0):
    """設置起始關卡"""
    if type(number) != type(3) : number = 1
    if number <= 0 :number = 1
    wawa.level_number = number - 1
    wawa.resetbombs()
    wawa.display_info() #顯示信息


"""定義別名"""
前進 = 走你 = fd = qianjin = qj = go = forward
後退 = 倒退 = bk = daotui = dt = back = backward
右轉 = 向右 = rt = right
左轉 = 向左 = lt = left
關卡 = 設關卡 = 設定關卡 = 設置關卡 = 設置關卡號 = setlevel = set_level
等待 = 延時  = sleep
跳 = 跳躍 = jump

pygame = __init_audio__()                  
screen = __init_screen__(__screen_width__,__screen_height__,"white",__gamename__)   # 新建屏幕對象
if screen==None:sys.exit(0)

__game_mode__ = __load_cfg__("cfg.txt")

#-------------------------畫格子 ----------------------------------
"""畫一個5x9的格子,每個格子的像素爲50x50。
"""
__draw_grid__((-225,250),(225,0),(5,9))       # 畫格子,起始座標,結束座標,行列數


#------------------------生成命令按鈕------------------------------
"""這段程序生成三行命令按鈕,每行有9個按鈕,從上到下。
第一行的按鈕是代碼娃娃的子程序1,它用橙色星星代表。用suborange列表保存。
第二行的按鈕是代碼娃娃的子程序2,它用綠色星星代表。用subgreen列表保存。
第三行的按鈕是代碼娃娃的主程序, 它用一封信代表。用main列表保存。

"""
__commandlist__ = ["前進","左轉","右轉","suborange","subgreen","跳躍","pass"]
suborange,subgreen,main = __make_button__() # 生成橙,綠,主程序指列按鈕    

#----------------------炸彈 ----------------------------------
"""本段程序新建12個炸彈

"""
def __manual_bomb__():
    """按z鍵人工生成一個炸彈,在(0,-25)坐置"""
    zd = Bomb(__explode_image_list__,__explosion_sound__)
    zd.goto(0,-25)
    zd.showturtle()
    bombs.append(zd)
    
if __game_mode__ == 1:
    bombs = [Bomb(__explode_image_list__,__explosion_sound__) for i in range(36)]   # 新建36個炸彈
else:
    bombs = [Bomb(__explode_image_list__,__explosion_sound__) for i in range(12)]   # 新建12個炸彈
screen.onkeypress(__manual_bomb__,"z") #按z鍵可人工生成一顆炸彈
#----------------------6、房子 ----------------------------------
"""本段程序生成房子對象,參數爲房子造型列表,水晶聲,炸彈列表
"""

house = House(__house_list__,__crystalsound__,bombs)                 # 新建房子對象

#----------------------娃娃 ----------------------------------
"""本段程序生成娃娃對象,它的參數如下:
  __wawagif__:它是已經註冊到形狀列表的娃娃的4個造型。
  main:娃娃的要執行的主程序指令表。
  suborange:娃娃的主程序將調用的子程序1。
  subgreen:娃娃的程序將調用的子程序2。
  house:娃娃可訪問房子。
  __allcoordinates__:所有格子中央座標點。洗牌後就是隨機的,用於隨機放置炸彈。
  bombs:娃娃可訪問所有炸彈。
  __sounds__:娃娃的音效列表。     

"""
__allcoordinates__=[]                           # 所有格子的座標中心點
__gridx__,__gridy__ = -200,25                   # 左下角格子中心點座標
for __x__ in range(__gridx__,201,50):
    for __y__ in range(__gridy__,226,50):
        #print("(",__x__,",",__y__,")",end = ",")
        __allcoordinates__.append((__x__,__y__))
    #print()

__ps__ = __wawagif__,main,suborange,subgreen,house,__allcoordinates__,bombs,__sounds__,__game_mode__,Command
wawa =Wawa(*__ps__)                   # 新建娃對象,它的默認的座標爲(-200,25)

if __game_mode__ != 1 :               # 隨機模式
    wawa.resetbombs()                 # 重置炸彈的位置
else:
    set_level()


#----------------------放幾個標誌----------------------------------
__flag_images__ = [ __images_folder__ + "橙色星.gif", __images_folder__ + "綠色星.gif", __images_folder__ + "信封.gif"]
[screen.addshape(image) for image in __flag_images__]
__flag__ = Turtle(visible = False)   # 初始狀態是不可見的
__flag__.pencolor("orange")
__flag__.penup()
__x__,__y__ = 0,270
__flag__.goto(__x__,__y__)
__flag__.write(__gamename__,align='center',font=("黑體",16,"normal"))

__x__,__y__ = -260,-100
for __i__ in range(3):        
    __flag__.shape(__flag_images__[__i__])
    __flag__.goto(__x__,__y__)
    if __i__ < 2 : __flag__.stamp()    # 最後一個不蓋章,要不然無法單擊信封實現運行指令
    __y__ = __y__ - 50
    
__envelopex__ = __flag__.xcor()
__envelopey__ = __flag__.ycor()

__x__,__y__ = -230,-110

__flag__.pencolor("gray")
for __i__ in range(3):         
    __flag__.goto(__x__,__y__)
    __flag__.write("=",align='center',font=("Arial",14,"normal"))
    __y__ = __y__ - 50

__flag__.goto(__envelopex__,__envelopey__)
__flag__.showturtle()
__flag__.onclick(lambda __x__,__y__:wawa.execute())    # 單擊左鍵執行main指令集
__flag__.onclick(lambda __x__,__y__:wawa.gohome(),3)   # 單擊右鍵回到左下角格子

#----------------------播放與靜音按鈕 ----------------------------------
"靜音按鈕,起始狀態是on,單擊後放音樂。造型列表爲:__mutebutton__"
__mute_index__ = 0
def __alt_music_status__():
    """播放音樂或停止播放"""
    global __mute_index__
    
    __mutebutton__.shape(__mute_list__[1 -__mute_index__])
    if __mute_index__ == 1:
        playmusic()
    else:
        stopmusic()
    __mute_index__ = 1 - __mute_index__
    
__x__,__y__ = -260,-250
__mutebutton__ = Turtle(shape = __mute_list__[0],visible = False) # 初始狀態是不可見的
__mutebutton__.penup()
__mutebutton__.goto(__x__,__y__)
__mutebutton__.showturtle()
__mutebutton__.onclick(lambda x,y:__alt_music_status__())
playmusic()
screen.listen() 

if __name__ == "__main__":

     def open_url(x,y):
         #print(x,",",y)
         if x>=-328 and x<=323 and y>=-321 and y<=-270:             
             webbrowser.open("http://www.scratch8.net/wawa_python.php")
         
     copyrighter  = Turtle(visible=False)
     copyrighter.penup()
     copyrighter.color("gray")
     copyrighter.sety(-300)
     copyrighter.write("風火輪少兒編程出品,操作說明:http://www.scratch8.net/wawa_python.php",align='center',move=False,font=("楷體",12,"normal"))
     screen.onclick(open_url)     
     screen.mainloop()




    

 

Python編程娃娃源代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章