day-012--圖形用戶界面和游戲開發(fā)

圖形用戶界面和游戲開發(fā)

主要介紹下tkinterPygame 兩個模塊, 真搞gui有用專業(yè)點的票摇,比如 wxPython亥揖、PyQtPyGTK之類的杈湾,學(xué)習(xí)pygame好好理解面向?qū)ο笞兂山馐嫦敫阌螒蛞彩强梢缘模偷猛氈铝搜芯?/p>

wxpython 可以看這一篇https://www.cnblogs.com/morries123/p/8568666.html

1. 基于tkinter模塊的GUI

GUI是圖形用戶界面的縮寫漆撞,圖形化的用戶界面對使用過計算機的人來說應(yīng)該都不陌生殴泰,在此也無需進行贅述。Python默認的GUI開發(fā)模塊是tkinter(在Python 3以前的版本中名為Tkinter)浮驳,從這個名字就可以看出它是基于Tk的悍汛,Tk是一個工具包,最初是為Tcl設(shè)計的至会,后來被移植到很多其他的腳本語言中离咐,它提供了跨平臺的GUI控件。

基本上使用tkinter來開發(fā)GUI應(yīng)用需要以下5個步驟:

    1. 導(dǎo)入tkinter模塊中我們需要的東西奉件。
    1. 創(chuàng)建一個頂層窗口對象并用它來承載整個GUI應(yīng)用宵蛀。
    1. 在頂層窗口對象上添加GUI組件。
    1. 通過代碼將這些GUI組件的功能組織起來县貌。
    1. 進入主事件循環(huán)(main loop)术陶。

大概看下,后面再專門搞個獨立分支研究gui:


import tkinter
import tkinter.messagebox


def main():
    flag = True

    # 修改標(biāo)簽上的文字
    def change_label_text():
        nonlocal flag
        flag = not flag
        color, msg = ('red', 'Hello, world!')\
            if flag else ('blue', 'Goodbye, world!')
        label.config(text=msg, fg=color)

    # 確認退出
    def confirm_to_quit():
        if tkinter.messagebox.askokcancel('溫馨提示', '確定要退出嗎?'):
            top.quit()

    # 創(chuàng)建頂層窗口
    top = tkinter.Tk()
    # 設(shè)置窗口大小
    top.geometry('240x160')
    # 設(shè)置窗口標(biāo)題
    top.title('小游戲')
    # 創(chuàng)建標(biāo)簽對象并添加到頂層窗口
    label = tkinter.Label(top, text='Hello, world!', font='Arial -32', fg='red')
    label.pack(expand=1)
    # 創(chuàng)建一個裝按鈕的容器
    panel = tkinter.Frame(top)
    # 創(chuàng)建按鈕對象 指定添加到哪個容器中 通過command參數(shù)綁定事件回調(diào)函數(shù)
    button1 = tkinter.Button(panel, text='修改', command=change_label_text)
    button1.pack(side='left')
    button2 = tkinter.Button(panel, text='退出', command=confirm_to_quit)
    button2.pack(side='right')
    panel.pack(side='bottom')
    # 開啟主事件循環(huán)
    tkinter.mainloop()


if __name__ == '__main__':
    main()

效果:

image.png

2.使用Pygame進行游戲開發(fā)

這段直接搬作者的了煤痕,主要學(xué)習(xí)思想

Pygame是一個開源的Python模塊梧宫,專門用于多媒體應(yīng)用(如電子游戲)的開發(fā),其中包含對圖像杭攻、聲音祟敛、視頻、事件兆解、碰撞等的支持。Pygame建立在SDL的基礎(chǔ)上跑揉,SDL是一套跨平臺的多媒體開發(fā)庫锅睛,用C語言實現(xiàn),被廣泛的應(yīng)用于游戲历谍、模擬器现拒、播放器等的開發(fā)。而Pygame讓游戲開發(fā)者不再被底層語言束縛望侈,可以更多的關(guān)注游戲的功能和邏輯印蔬。

大神給的例子是大球吃小球,我改了部分bug脱衙,加了點東西進去侥猬,

from enum import Enum, unique
from math import sqrt,cos,sin,pi
from random import randint
import easygui as g
import pygame


class BallType:
    normal,diminish,split,hero = range(4)


class Direction:
    left, ltop, top, rtop,right, rbottom, bottom, lbottom, nothing = range(9)
    dict_direct = {
        left: [(10, 170),False],
        ltop: [(10, 80), True],
        top: [(10, 170), True],
        rtop: [(100, 170),True],
        right: [(190, 350), False],
        rbottom: [(170, 260), True],
        bottom: [(190, 350), True],
        lbottom: [(280, 350), True],
        nothing: [(0, 360), True]
    }


def random_ball(balltype,x,y,radius):
    sx, sy = randint(-10, 10), randint(-10, 10)
    color = Color.random_color()
    # 在點擊鼠標(biāo)的位置創(chuàng)建一個球(大小例驹、速度和顏色隨機)
    if balltype is BallType.hero:
        global hero_ball
        hero_ball = Ball(balltype, x, y, radius, sx, sy, color)
        balls.append(hero_ball)
    else:
        ball = Ball(balltype, x, y, radius, sx, sy, color)
        balls.append(ball)
    # 將球添加到列表容器中
    # balls.append(ball)


@unique
class Color(Enum):
    """顏色"""

    RED = (255, 0, 0)
    GREEN = (0, 255, 0)
    BLUE = (0, 0, 255)
    BLACK = (0, 0, 0)
    WHITE = (255, 255, 255)
    GRAY = (242, 242, 242)

    @staticmethod
    def random_color():
        """獲得隨機顏色"""
        r = randint(0, 255)
        g = randint(0, 255)
        b = randint(0, 255)
        return (r, g, b)


class Ball(object):
    """球"""
    dirchange = True
    direction = 8;
    go_direction = 8;
    direction_x = 0
    direction_y = 0
    def __init__(self, balltype, x, y, radius, sx, sy, color=Color.RED):
        """初始化方法"""
        self.x = x
        self.y = y
        self.radius = radius
        self.sx = sx
        self.sy = sy
        self.color = color
        self.alive = True
        self.balltype = balltype

    def do_direction(self,screen):
        degree = randint(Direction.dict_direct[self.direction][0][0],Direction.dict_direct[self.direction][0][1])
        if Direction.dict_direct[self.direction][1]:
            degree = (degree / 180 * pi)
            self.direction_x = cos(degree)
            self.direction_y = sin(degree)
        else:
            degree = (degree / 180 * pi)
            self.direction_x = sin(degree)
            self.direction_y = cos(degree)

        self.go_direction = self.direction

    def move(self, screen):
        """移動"""
        if self.dirchange:
            self.dirchange = False
            self.do_direction(screen)

        maxspeed = 900/self.radius
        if maxspeed > 30:
            maxspeed = 30
        self.x += int(maxspeed * self.direction_x)
        self.y += int(maxspeed * self.direction_y)

        if self.x - self.radius <= 0 and self.y - self.radius <= 0:  # ltop
            if self.go_direction is not Direction.ltop:
                self.dirchange = True
                self.direction = Direction.ltop

        elif self.x - self.radius > 0 >= self.y - self.radius and self.x + self.radius < screen.get_width():  # top
            if self.go_direction is not Direction.top:
                self.dirchange = True
                self.direction = Direction.top

        elif  self.x + self.radius >= screen.get_width() and self.y - self.radius <= 0:  # rtop
            if self.go_direction is not Direction.rtop:
                self.dirchange = True
                self.direction = Direction.rtop

        elif self.x + self.radius >= screen.get_width() and self.y+self.radius < screen.get_height() and self.y - self.radius > 0:  # right
            if self.go_direction is not Direction.right:
                self.dirchange = True
                self.direction = Direction.right

        elif self.x + self.radius >= screen.get_width() and self.y + self.radius >= screen.get_height():  # rbottom
            if self.go_direction is not Direction.rbottom:
                self.dirchange = True
                self.direction = Direction.rbottom

        elif self.x - self.radius > 0 and self.x + self.radius < screen.get_width() and self.y + self.radius >= screen.get_height():  # bottom
            if self.go_direction is not Direction.bottom:
                self.dirchange = True
                self.direction = Direction.bottom

        elif self.x - self.radius <= 0 and self.y + self.radius >= screen.get_height(): # lbottom
            if self.go_direction is not Direction.lbottom:
                self.dirchange = True
                self.direction = Direction.lbottom

        elif self.x - self.radius <= 0 < self.y - self.radius and self.y + self.radius < screen.get_height():  # left
            if self.go_direction is not Direction.left:
                self.dirchange = True
                self.direction = Direction.left

    def eat(self, other):
        """吃其他球"""

        if self.alive and other.alive and self != other:
            dx, dy = self.x - other.x, self.y - other.y
            distance = sqrt(dx ** 2 + dy ** 2)
            if distance < max(self.radius, other.radius )\
                    and self.radius > other.radius:
                if other.balltype is BallType.normal or other.balltype is BallType.hero:
                    self.radius = self.radius + int(other.radius * 0.146)
                    if self.radius > 300:
                        self.radius = 300
                elif other.balltype is BallType.diminish:
                    self.diminish()
                elif other.balltype is BallType.split:
                    self.split()

                other.alive = False


    def draw(self, screen):
        """在窗口上繪制球"""
        # 不能讓hero 出屏
        if self.balltype is BallType.hero:
            if self.x <= 0:
                self.x = 0
            if self.y <= 0:
                self.y = 0
            if self.x >= screen.get_width():
                self.x = screen.get_width()
            if self.y >= screen.get_height():
                self.y = screen.get_height()

        if self.balltype is BallType.normal or self.balltype is BallType.hero:
            pygame.draw.circle(screen, self.color,
                           (self.x, self.y), int(self.radius), 0)
        elif self.balltype is BallType.diminish:
            pygame.draw.rect(screen,self.color,[self.x, self.y, 20,20])
        elif self.balltype is BallType.split:
            pygame.draw.ellipse(screen,self.color,[self.x, self.y, 20, 10])

    def diminish(self):
        if self.radius > 30:
            self.radius = int(self.radius/2)

    def split(self):
        if self.radius > 50:
            radius_tmp = self.radius
            if self.balltype is BallType.hero:
                self.radius = int(self.radius/2)
                if self.radius < 30:
                    self.radius = 30
            else:
                self.radius = int(self.radius/5)
                self.alive = False

            for index in range(0,20):
                degree = 18*index/180*pi
                x = self.radius*cos(degree) + self.x
                y = self.radius*sin(degree) + self.y
                random_ball(BallType.normal,int(x),int(y),self.radius)
                # radius = self.radius
                # color = self.color
                # sx = x
                # sy = y
                # ball = Ball(x, y, radius, sx, sy, color)
                # balls.append(ball)
            if self.balltype is not BallType.hero:
                balls.remove(self)


def main():
    # 定義用來裝所有球的容器
    global balls
    balls = []
    # global hero_ball


    ishavehero = False
    ishavehero_old = False
    # hero_ball = Ball()
    # global hero_ball_x
    # global hero_ball_y
    # 初始化導(dǎo)入的pygame中的模塊
    pygame.init()
    # 初始化用于顯示的窗口并設(shè)置窗口尺寸
    screen = pygame.display.set_mode((1800, 900))

    # print(screen.get_height())
    # 設(shè)置當(dāng)前窗口的標(biāo)題
    pygame.display.set_caption('大球吃小球')
    running = True
    sum_palce = 0
    auto_out_cnt = 0
    msg = ''
    bFail = False
    # 開啟一個事件循環(huán)處理發(fā)生的事件

    # random_ball(BallType.hero, randint(100, 500), randint(100, 500), randint(10, 100))
    while running:
        # 從消息隊列中獲取事件并對事件進行處理
        auto_out_cnt += 1
        if bFail :
            bFail = False
            button_choices = g.buttonbox(msg, '游客', choices=('繼續(xù)', '退出'))
            if button_choices == '繼續(xù)':
                balls.clear()
                ishavehero = False
                msg = ''
                ishavehero_old = False
                continue
            elif button_choices == '退出':
                return 0
        if auto_out_cnt >= 20:
            if len(balls) < 30:
                random_ball(BallType.normal, randint(100, 500, ), randint(100, 500), randint(10, 100))
            auto_out_cnt = 0
            if ishavehero:
                if sum_palce > screen.get_height() * screen.get_width() / 4 \
                    or hero_ball.radius * hero_ball.radius * pi > screen.get_height() * screen.get_width() / 4:
                    if sum_palce < hero_ball.radius * hero_ball.radius * pi:
                        msg = '你贏了'
                    else:
                        msg = '你輸了'
                        ishavehero = False
                    bFail = True
            elif ishavehero is False and ishavehero_old is True:
                msg = '你輸了'
                bFail = True
            if  ishavehero_old is True:
                if hero_ball.alive is False:
                    msg = '你輸了'
                    bFail = True


        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False

            # 處理鼠標(biāo)事件的代碼
            if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                # 獲得點擊鼠標(biāo)的位置
                x,y = event.pos
                # hero_ball.
                # random_ball(BallType.normal, x, y,randint(10, 100))
                if ishavehero is False:
                    random_ball(BallType.hero, x, y, randint(50, 100))
                    random_ball(BallType.split, randint(100, 500), randint(100, 500), randint(10, 100))
                    random_ball(BallType.diminish, randint(100, 500), randint(100, 500), randint(10, 100))
                    ishavehero = True
                    ishavehero_old = True
            if ishavehero :
                hero_ball.x,hero_ball.y = pygame.mouse.get_pos()

        screen.fill((255, 255, 255))
        # 取出容器中的球 如果沒被吃掉就繪制 被吃掉了就移除
        sum_palce = 0
        for ball in balls:
            if ball.balltype is BallType.normal:
                sum_palce += ball.radius*ball.radius*pi
            if ball.alive:
                ball.draw(screen)
            else:
                if ball.balltype is not BallType.normal:
                    random_ball(ball.balltype,randint(100, 500,), randint(100, 500),randint(10, 100))
                balls.remove(ball)

        pygame.display.flip()
        # 每隔50毫秒就改變球的位置再刷新窗口
        pygame.time.delay(50)



        for ball in balls:
            if ball.balltype is BallType.normal:
                ball.move(screen)
            # 檢查球有沒有吃到其他的球
            for other in balls:
                if ball.balltype is BallType.normal or ball.balltype is BallType.hero:
                    ball.eat(other)
        for ball in balls:
            if ball.alive:
                ball.draw(screen)
            else:
                if ball.balltype is not BallType.normal and ball.balltype is not BallType.hero:
                    random_ball(ball.balltype, randint(100, 500, ), randint(100, 500), randint(10, 100))
                balls.remove(ball)

def printsin(degree):
    print('sin(',degree,') = ',sin(degree/180*pi))

def printcos(degree):
    print('cos(', degree, ') = ', cos(degree / 180 * pi))

def printsc(degree):
    printcos(degree)
    printsin(degree)

if __name__ == '__main__':
    while True:
        ret = main()
        if ret is 0:
            exit(0)

效果:

image.png

目前是點擊之后可以出一個hero角色,然后又矩形吃了會變小退唠,橢圓吃了會分裂鹃锈,達到北京四分之一就結(jié)束了,回去重新搞一下瞧预,加點分裂之后還是跟著主體屎债,然后讓這東東智能點,變成策略游戲

文集傳送門 學(xué)習(xí)python100天


整個學(xué)習(xí)python100天的目錄傳送門


無敵分割線


再最后面附上大神的鏈接
傳送門

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末垢油,一起剝皮案震驚了整個濱河市盆驹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌滩愁,老刑警劉巖躯喇,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異惊楼,居然都是意外死亡玖瘸,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門檀咙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雅倒,“玉大人,你說我怎么就攤上這事弧可∶锵唬” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵棕诵,是天一觀的道長裁良。 經(jīng)常有香客問我,道長校套,這世上最難降的妖魔是什么价脾? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮笛匙,結(jié)果婚禮上侨把,老公的妹妹穿的比我還像新娘。我一直安慰自己妹孙,他們只是感情好秋柄,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蠢正,像睡著了一般骇笔。 火紅的嫁衣襯著肌膚如雪谆焊。 梳的紋絲不亂的頭發(fā)上穷遂,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天,我揣著相機與錄音,去河邊找鬼汹来。 笑死摔握,一個胖子當(dāng)著我的面吹牛盖彭,可吹牛的內(nèi)容都是我干的不见。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼持寄,長吁一口氣:“原來是場噩夢啊……” “哼源梭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起稍味,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤废麻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后模庐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烛愧,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年掂碱,在試婚紗的時候發(fā)現(xiàn)自己被綠了怜姿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡疼燥,死狀恐怖沧卢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情醉者,我是刑警寧澤但狭,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站撬即,受9級特大地震影響立磁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜剥槐,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一唱歧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧粒竖,春花似錦迈喉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽孩革。三九已至岁歉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背锅移。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工熔掺, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人非剃。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓置逻,卻偏偏與公主長得像,于是被迫代替她去往敵國和親备绽。 傳聞我的和親對象是個殘疾皇子券坞,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350