day-012--图形用户界面和游戏开发

图形用户界面和游戏开发

主要介绍下tkinterPygame 两个模块, 真搞gui有用专业点的,比如 wxPythonPyQtPyGTK之类的,学习pygame好好理解面向对象变成,真想搞游戏也是可以的,就得往细致了研究

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

1. 基于tkinter模块的GUI

GUI是图形用户界面的缩写,图形化的用户界面对使用过计算机的人来说应该都不陌生,在此也无需进行赘述。Python默认的GUI开发模块是tkinter(在Python 3以前的版本中名为Tkinter),从这个名字就可以看出它是基于Tk的,Tk是一个工具包,最初是为Tcl设计的,后来被移植到很多其他的脚本语言中,它提供了跨平台的GUI控件。

基本上使用tkinter来开发GUI应用需要以下5个步骤:

    1. 导入tkinter模块中我们需要的东西。
    1. 创建一个顶层窗口对象并用它来承载整个GUI应用。
    1. 在顶层窗口对象上添加GUI组件。
    1. 通过代码将这些GUI组件的功能组织起来。
    1. 进入主事件循环(main loop)。

大概看下,后面再专门搞个独立分支研究gui:


import tkinter
import tkinter.messagebox


def main():
    flag = True

    # 修改标签上的文字
    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()

    # 创建顶层窗口
    top = tkinter.Tk()
    # 设置窗口大小
    top.geometry('240x160')
    # 设置窗口标题
    top.title('小游戏')
    # 创建标签对象并添加到顶层窗口
    label = tkinter.Label(top, text='Hello, world!', font='Arial -32', fg='red')
    label.pack(expand=1)
    # 创建一个装按钮的容器
    panel = tkinter.Frame(top)
    # 创建按钮对象 指定添加到哪个容器中 通过command参数绑定事件回调函数
    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')
    # 开启主事件循环
    tkinter.mainloop()


if __name__ == '__main__':
    main()

效果:

image.png

2.使用Pygame进行游戏开发

这段直接搬作者的了,主要学习思想

Pygame是一个开源的Python模块,专门用于多媒体应用(如电子游戏)的开发,其中包含对图像、声音、视频、事件、碰撞等的支持。Pygame建立在SDL的基础上,SDL是一套跨平台的多媒体开发库,用C语言实现,被广泛的应用于游戏、模拟器、播放器等的开发。而Pygame让游戏开发者不再被底层语言束缚,可以更多的关注游戏的功能和逻辑。

大神给的例子是大球吃小球,我改了部分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()
    # 在点击鼠标的位置创建一个球(大小、速度和颜色随机)
    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
    # 初始化导入的pygame中的模块
    pygame.init()
    # 初始化用于显示的窗口并设置窗口尺寸
    screen = pygame.display.set_mode((1800, 900))

    # print(screen.get_height())
    # 设置当前窗口的标题
    pygame.display.set_caption('大球吃小球')
    running = True
    sum_palce = 0
    auto_out_cnt = 0
    msg = ''
    bFail = False
    # 开启一个事件循环处理发生的事件

    # 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=('继续', '退出'))
            if button_choices == '继续':
                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

            # 处理鼠标事件的代码
            if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                # 获得点击鼠标的位置
                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角色,然后又矩形吃了会变小,椭圆吃了会分裂,达到北京四分之一就结束了,回去重新搞一下,加点分裂之后还是跟着主体,然后让这东东智能点,变成策略游戏

文集传送门 学习python100天


整个学习python100天的目录传送门


无敌分割线


再最后面附上大神的链接
传送门

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352