图形用户界面和游戏开发
主要介绍下tkinter
和 Pygame
两个模块, 真搞gui
有用专业点的,比如 wxPython
、PyQt
、PyGTK
之类的,学习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个步骤:
- 导入tkinter模块中我们需要的东西。
- 创建一个顶层窗口对象并用它来承载整个GUI应用。
- 在顶层窗口对象上添加GUI组件。
- 通过代码将这些GUI组件的功能组织起来。
- 进入主事件循环(main loop)。
大概看下,后面再专门搞个独立分支研究gui:
# import tkinter
# tk = tkinter.Tk()
# tk.title('test jin')
#
# lan = ['c','c++','python','php']
# movie = ['css','jq','bt']
#
# lista = tkinter.Listbox(tk)
# listb = tkinter.Listbox(tk)
#
# for item in lan:
# lista.insert(0,item)
#
# for item in movie:
# listb.insert(0,item)
#
# label = tkinter.Label(tk,{'text' :'hello'})
#
#
# lista.pack()
# listb.pack()
# label.pack()
#
#
# tk.mainloop()
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()
效果:
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)
效果:
目前是点击之后可以出一个hero角色,然后又矩形吃了会变小,椭圆吃了会分裂,达到北京四分之一就结束了,回去重新搞一下,加点分裂之后还是跟着主体,然后让这东东智能点,变成策略游戏
文集传送门 学习python100天
整个学习python100天的目录传送门
无敌分割线
再最后面附上大神的链接
传送门