用python尝试做游戏(二)

系列文章目录

用python尝试做游戏(一)
用python尝试做游戏(二)



目标

之前记录了极度基础的界面怎么写,以及基础的键盘鼠标交互如何可以进行,接下来将围绕以下内容调查学习并记录:鼠标在画布(界面)的定位、画布中组件的定位(自身边界——泛)、简单的碰撞引擎、物理引擎、画布上网格显示、画布上或者界面中的数据显示(时间) 、数据的自动更新(时间)、


一、鼠标在界面中的定位

我找到三个 pyautogui,pynput,普通的tkinter。

pyautogui

pip install pyautogui
import pyautogui as pag

try:
    while True:
        print("Press Ctrl-C to end")
        screenWidth, screenHeight = pag.size()  # 获取屏幕的尺寸
        x, y = pag.position()  # 返回鼠标的坐标
        print("Screen size: (%s %s),  Position : (%s, %s)\n" % (screenWidth, screenHeight, x, y))  # 打印坐标
 
        time.sleep(1)  # 每个1s中打印一次 , 并执行清屏

except KeyboardInterrupt:
    print('end')

pyautogui的文档 https://pyautogui.readthedocs.io/en/latest/

问题移动非常快会缺失,原因未知,待研究。
猜测,可能是因为移动速度大于运算处理速度???
不过问题应该不大,控制一下刷新频率就行,反正人眼频率分辨率很低,两三百撑死了。
游戏的话,也还好。
(截图数据都是我刻意找到的,平常很正常)
在这里插入图片描述

pynput

官方文档地址

https://pynput.readthedocs.io/en/latest/mouse.html#pynput.mouse.Controller.move

tkinter

居然还是bind!!!!!!!!!!
这个不错的样子
而且不局限于画布,只要界面大小没锁死,拉伸以后还可以,而且不能越界。
(不过刷新频率不确定)
在这里插入图片描述

  • 如图所示,移动非常快会缺失,原因未知,待研究。可能和window.mainloop()循环有关。
#读取当前鼠标位置 界面里的位置 像素点
def b(event):
    print(event.x,event.y)

window.bind('<Motion>',b)          

关于pyautogui和tkinter 鼠标位置刷新速度的的实验(续 )注:不完整

一开始生成,点击左键后,开始绘画鼠标在画布上的轨迹,像素点,单位1。
在这里插入图片描述
如图绘画情况,移速满则密集,快则疏松。
在这里插入图片描述
示意代码,但是不知道为啥,一次点击后,b就一直运行?加了一次if条件没啥用。
是不是得再设个全局变量,就是点击一次,bb里记个数,加一。b里面这个数 if == 1就运行画画,然后画完 这个变量减一。

#读取当前鼠标位置 相对位置
def b(ev):
    line = canvas.create_line(ev.x, ev.y, ev.x+1, ev.y+1,fill='yellow')
 
def bb_(evv):
    if evv.num == 1:
            window.bind('<Motion>',b)

window.bind("<Button-1>",bb_)  

确实,按照上面的说法试了一下,ok就是点一下画一个点。还能再改吧,或者查查有没有其他方式,不过我记得脚本的一些库中,有判断是否鼠标按下,有没有抬起等等的功能,用到再查一下。
pyautogui里好像就有。
在这里插入图片描述


ma = 0
#读取当前鼠标位置 相对位置
def b(ev):
    global ma
    if ma == 1:
        ma = ma -1
        line = canvas.create_line(ev.x, ev.y, ev.x+1, ev.y+1,fill='yellow')
 
def bb_(evv):
    global ma
    window.bind('<Motion>',b)
    ma = ma +1 

window.bind("<Button-1>",bb_)      

反正也写了,顺便看看pyautogui
在这里插入图片描述
好吧,似乎差不多。
不过如果是画布,得设置一下比例相对位置什么的,因为这个返回的坐标是电脑屏幕的。
代码差不多。

#读取当前鼠标位置 据对位置
def b(ev):
    e_x, e_y = pag.position()  # 返回鼠标的坐标
    line = canvas.create_line(e_x, e_y, e_x+1, e_y+1,fill='yellow')
 
def bb_(evv):
    window.bind('<Motion>',b)
window.bind("<Button-1>",bb_)    

感觉 似乎 对吧 电脑自带的画图,再加加改改,搞俩按钮菜单,做个数据保存打开什么的,也能做?!!! 就做出来了?

二、画布中组件的定位

思路

想法 一种是笨办法,建个三维数组,反正是画网格,差不多。然后二维是对应显示器坐标嘛。再有一维就是标记。各种标记。
或者字典??字典好像可以干这个,我等等查查吧。
那么ok,现在得想着,按标记画图,这样才好确定啥是啥,画图的时候就记下标记,感觉省事。

place 绝对位置——参数:横坐标x,纵坐标y
关于画图 有绘图库Turtle。

#画一个像素块 给起始位置,向正方向画图,(目前多数是屏幕右下)画布的相对位置,左上角是0,0 默认黄色
def paint_point(x,y,size):
    line = canvas.create_line(x, y, x+size, y+size,fill='yellow')

#这个是测试了一下,返回参数的情况,想看看如果line画完,外部能不能记录。
def aaa():
    return 8
x = aaa()
print (x)

然后 我记得好像可以标记,就是本身有,查了查 欧克,get。

canvas(...)
image = canvas.create_image(250, 0, anchor='n',image=image_file)

line = canvas.create_line(2, 2, 3,3,fill='yellow',tag = 'g1')
canvas.pack()
#全部的列出来 1,2。。。。 注意 这个的运行速度很慢很慢!!!!!!!
print(canvas.find_all())     
# 访问图形项的id,也就是编号、生成的顺序
print(line) # 2
# 根据指定tag该tag对应的所有图形项 即编号第几个
print(canvas.find_withtag('g1')) # (2)
canvas.dtag(1, 't1') # 删除id为1的图形项上名为t1的tag
canvas.dtag(line, 'g1') # 删除id为line的图形项上名为g1的tag
canvas.delete(line) # 删除对应的图形,可以是前面的变量名、标签、id等等

在这里插入图片描述

再回顾一下思路,先标记识别(后端,不是鼠标指,可以但是目前好像不需要)区分图形,可以选择图形,删除图形。然后要可以查找图形,进一步要判断图形的位置。

.clear()
clear方法清除字典中所有的项。这个是原地操作(类似于list.sort),所以无返回值(或返回None)

deque队列

try except 语句的执行流程如下:
首先执行 try 中的代码块,如果执行过程中出现异常,系统会自动生成一个异常类型,并将该异常提交给 Python 解释器,此过程称为捕获异常。
当 Python 解释器收到异常对象时,会寻找能处理该异常对象的 except 块,如果找到合适的 except 块,则把该异常对象交给该 except 块处理,这个过程被称为处理异常。如果 Python 解释器找不到处理异常的 except 块,则程序运行终止,Python 解释器也将退出。
try:
    可能产生异常的代码块
except [ (Error1, Error2, ... ) [as e] ]:
    处理异常的代码块1
except [ (Error3, Error4, ... ) [as e] ]:
    处理异常的代码块2
except  [Exception]:
    处理其它异常

该格式中,[] 括起来的部分可以使用,也可以省略。其中各部分的含义如下:
(Error1, Error2,...)(Error3, Error4,...):其中,Error1、Error2、Error3 和 Error4 都是具体的异常类型。显然,一个 except 块可以同时处理多种异常。
[as e]:作为可选参数,表示给异常类型起一个别名 e,这样做的好处是方便在 except 块中调用异常类型。
[Exception]:作为可选参数,可以代指程序可能发生的所有异常情况,其通常用在最后一个 except 块。

三、附录

知识再来一遍

background(bg)      背景色;
    foreground(fg)       前景色;
    borderwidth       组件边框宽度;
    width             组件宽度;
    height             高度;
    bitmap             位图;
    image             图片;
绘图:
    create_arc          圆弧;
    create_bitmap      绘制位图,支持XBM;
    create_image       绘制图片,支持GIF(x,y,image,anchor);
    create_line         绘制支线;
    create_oval;        绘制椭圆;
    create_polygon     绘制多边形(坐标依次罗列,不用加括号,还有参数,fill,outline);
    create_rectangle   绘制矩形((a,b,c,d),值为左上角和右下角的坐标);
    create_text         绘制文字(字体参数font,);
    create_window      绘制窗口;
    delete              删除绘制的图形;
    itemconfig          修改图形属性,第一个参数为图形的ID,后边为想修改的参数;
    move               移动图像(140),1为图像对象,4为横移4像素,0为纵移像素,然后用
    root.update()刷新即可看到图像的移动,为了使多次移动变得可视,最好加上time.sleep()函数;
    只要用create_方法画了一个图形,就会自动返回一个ID,创建一个图形时将它赋值给一个变量,需要ID
    时就可以使用这个变量名。
    coords(ID)          返回对象的位置的两个坐标(4个数字元组);

对于按钮组件、菜单组件等可以在创建组件时通过command参数指定其事件处理函数。方法为bind;或者
用bind_class方法进行类绑定,bind_all方法将所有组件事件绑定到事件响应函数上。
复制代码
 10、菜单Menu
复制代码
参数: 
    tearoff          分窗,0为在原窗,1为点击分为两个窗口
    bg,fg           背景,前景
    borderwidth      边框宽度
    font              字体
    activebackgound   点击时背景,同样有activeforeground,activeborderwidth,disabledforeground
    cursor
    postcommand
    selectcolor      选中时背景
    takefocus
    title       
    type
    relief
   
方法:
    menu.add_cascade      添加子选项
    menu.add_command      添加命令(label参数为显示内容)
    menu.add_separator    添加分隔线
    menu.add_checkbutton  添加确认按钮
    delete                删除
复制代码
 11、事件关联
复制代码
bind(sequence,func,add)——
bind_class(className,sequence,func,add)
bind_all(sequence,func,add)
事件参数:  
sequence              所绑定的事件;
func                   所绑定的事件处理函数;
add                    可选参数,为空字符或‘+’;
className             所绑定的类;

鼠标键盘事件
    <Button-1>            鼠标左键按下,2表示中键,3表示右键;
    <ButtonPress-1>        同上;
    <ButtonRelease-1>    鼠标左键释放;
    <B1-Motion>           按住鼠标左键移动;
    <Double-Button-1>     双击左键;
    <Enter>               鼠标指针进入某一组件区域;
    <Leave>               鼠标指针离开某一组件区域;
    <MouseWheel>         滚动滚轮;
    <KeyPress-A>         按下A键,A可用其他键替代;
    <Alt-KeyPress-A>      同时按下alt和A;alt可用ctrl和shift替代;
    <Double-KeyPress-A>    快速按两下A;
    <Lock-KeyPress-A>     大写状态下按A;
   
窗口事件
    Activate             当组件由不可用转为可用时触发;
    Configure            当组件大小改变时触发;
    Deactivate          当组件由可用转变为不可用时触发;
    Destroy              当组件被销毁时触发;
    Expose              当组件从被遮挡状态中暴露出来时触发;
    Unmap              当组件由显示状态变为隐藏状态时触发;
    Map                  当组件由隐藏状态变为显示状态时触发;
    FocusIn              当组件获得焦点时触发;
    FocusOut            当组件失去焦点时触发;
    Property             当窗体的属性被删除或改变时触发;
    Visibility           当组件变为可视状态时触发;

响应事件
event对象(def function(event)):
    char                按键字符,仅对键盘事件有效;
    keycode            按键名,仅对键盘事件有效;
    keysym             按键编码,仅对键盘事件有效;
    num                鼠标按键,仅对鼠标事件有效;
    type                 所触发的事件类型;
    widget               引起事件的组件;
    width,heigh        组件改变后的大小,仅Configure有效;
    x,y                鼠标当前位置,相对于窗口;
    x_root,y_root       鼠标当前位置,相对于整个屏幕
复制代码
12、弹窗
复制代码
messagebox._show函数的控制参数:
    default         指定消息框按钮;
    icon            指定消息框图标;
    message        指定消息框所显示的消息;
    parent          指定消息框的父组件;
    title           标题;
    type            类型;

simpledialog模块参数:
    title           指定对话框的标题;
    prompt         显示的文字;
    initialvalue    指定输入框的初始值;

  filedialog    模块参数:
    filetype       指定文件类型;
    initialdir     指定默认目录;
    initialfile    指定默认文件;
    title         指定对话框标题

colorchooser模块参数:
    initialcolor    指定初始化颜色;
    title           指定对话框标题;
复制代码
13、字体(font)
一般格式:
('Times -10 bold')
('Times',10,'bold','italic')    依次表示字体、字号、加粗、倾斜


补充:
config            重新配置
label.config(font='Arial -%d bold' % scale.get())
依次为字体,大小(大小可为字号大小),加粗
tkinter.StringVar    能自动刷新的字符串变量,可用set和get方法进行传值和取值,类似的
还有IntVar,DoubleVar...

sys.stdout.flush()  刷新输出


然后 (这个的画布是很全的http://www.uml.org.cn/python/201912161.asp)

超全的画布标签操作!!!

# 绘制一个矩形框
rt = canvas.create_rectangle(40, 40, 300, 220,
outline='blue', width=2,
tag = ('t1', 't2', 't3', 'tag4')) # 为该图形项指定标签
# 访问图形项的id,也就是编号
print(rt) # 1
# 绘制一个椭圆
oval = canvas.create_oval(350, 50, 580, 200,
fill='yellow', width=0,
tag = ('g1', 'g2', 'g3', 'tag4')) # 为该图形项指定标签
# 访问图形项的id,也就是编号
print(oval) # 2
# 根据指定tag该tag对应的所有图形项
print(canvas.find_withtag('tag4')) # (1, 2)
# 获取指定图形项的所有tag
print(canvas.gettags(rt)) # ('t1', 't2', 't3', 'tag4')
print(canvas.gettags(2)) # ('g1', 'g2', 'g3', 'tag4')
canvas.dtag(1, 't1') # 删除id为1的图形项上名为t1的tag
canvas.dtag(oval, 'g1') # 删除id为oval的图形项上名为g1的tag
# 获取指定图形项的所有tag
print(canvas.gettags(rt)) # ('tag4', 't2', 't3')
print(canvas.gettags(2)) # ('tag4', 'g2', 'g3')
# 为所有图形项添加tag
canvas.addtag_all('t5')
print(canvas.gettags(1)) # ('tag4', 't2', 't3', 't5')
print(canvas.gettags(oval)) # ('tag4', 'g2', 'g3', 't5')
# 为指定图形项添加tag
canvas.addtag_withtag('t6', 'g2')
# 获取指定图形项的所有tag
print(canvas.gettags(1)) # ('tag4', 't2', 't3', 't5')
print(canvas.gettags(oval)) # ('tag4', 'g2', 'g3', 't5', 't6')
# 为指定图形项上面的图形项添加tag, t2上面的就是oval图形项
canvas.addtag_above('t7', 't2')
print(canvas.gettags(1)) # ('tag4', 't2', 't3', 't5')
print(canvas.gettags(oval)) # ('tag4', 'g2', 'g3', 't5', 't6', 't7')
# 为指定图形项下面的图形项添加tag, g2下面的就是rt图形项
canvas.addtag_below('t8', 'g2')
print(canvas.gettags(1)) # ('tag4', 't2', 't3', 't5', 't8')
print(canvas.gettags(oval)) # ('tag4', 'g2', 'g3', 't5', 't6', 't7')
# 为最接近指定点的图形项添加tag,最接近360、90的图形项是oval
canvas.addtag_closest('t9', 360, 90)
print(canvas.gettags(1)) # ('tag4', 't2', 't3', 't5', 't8')
print(canvas.gettags(oval)) # ('tag4', 'g2', 'g3', 't5', 't6', 't7', 't9')
# 为位于指定区域内(几乎覆盖整个图形区)的最上面的图形项添加tag
canvas.addtag_closest('t10', 30, 30, 600, 240)
print(canvas.gettags(1)) # ('tag4', 't2', 't3', 't5', 't8')
print(canvas.gettags(oval)) # ('tag4', 'g2', 'g3', 't5', 't6', 't7', 't9', 't10')
# 为与指定区域内重合的最上面的图形项添加tag
canvas.addtag_closest('t11', 250, 30, 400, 240)
print(canvas.gettags(1)) # ('tag4', 't2', 't3', 't5', 't8')
print(canvas.gettags(oval)) # ('tag4', 'g2', 'g3', 't5', 't6', 't7', 't9', 't10', 't11')

图型操作!!!

from tkinter import *
from tkinter import colorchooser
import threading
# 创建窗口
window = Tk()
window.title('操作图形项')
# 创建并添加Canvas
canvas = Canvas(window, background='white', width=400, height=350)
canvas.pack(fill=BOTH, expand=YES)
# 该变量用于保存当前选中的图形项
current = None
# 该变量用于保存当前选中的图形项的边框颜色
current_outline = None
# 该变量用于保存当前选中的图形项的边框宽度
current_width = None
# 该函数用于高亮显示选中图形项(边框颜色会red、yellow之间切换)
def show_current():
# 如果当前选中项不为None
if current is not None:
# 如果当前选中图形项的边框色为red,将它改为yellow
if canvas.itemcget(current, 'outline') == 'red':
canvas.itemconfig(current, width=2,
outline='yellow')
# 否则,将颜色改为red
else:
canvas.itemconfig(current, width=2,
outline='red')
global t
# 通过定时器指定0.2秒之后执行show_current函数
t = threading.Timer(0.2, show_current)
t.start()
# 通过定时器指定0.2秒之后执行show_current函数
t = threading.Timer(0.2, show_current)
t.start()
# 分别创建矩形、椭圆、和圆
rect = canvas.create_rectangle(30, 30, 250, 200,
fill='magenta', width='0')
oval = canvas.create_oval(180, 50, 380, 180,
fill='yellow', width='0')
circle = canvas.create_oval(120, 150, 300, 330,
fill='pink', width='0')
bottomF = Frame(window)
bottomF.pack(fill=X,expand=True)
liftbn = Button(bottomF, text='向上',
# 将椭圆移动到它上面的item之上
command=lambda : canvas.tag_raise(oval, canvas.find_above(oval)))
liftbn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
lowerbn = Button(bottomF, text='向下',
# 将椭圆移动到它下面的item之下
command=lambda : canvas.tag_lower(oval, canvas.find_below(oval)))
lowerbn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
def change_fill():
# 弹出颜色选择框,让用户选择颜色
fill_color = colorchooser.askcolor(parent=window,
title='选择填充颜色',
# 初始颜色设置为椭圆当前的填充色(fill选项值)
color = canvas.itemcget(oval, 'fill'))
if fill_color is not None:
canvas.itemconfig(oval, fill=fill_color[1])
fillbn = Button(bottomF, text='改变填充色',
# 该按钮触发change_fill函数
command=change_fill)
fillbn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
def change_outline():
# 弹出颜色选择框,让用户选择颜色
outline_color = colorchooser.askcolor(parent=window,
title='选择边框颜色',
# 初始颜色设置为椭圆当前的边框色(outline选项值)
color = canvas.itemcget(oval, 'outline'))
if outline_color is not None:
canvas.itemconfig(oval, outline=outline_color[1],
width=4)
outlinebn = Button(bottomF, text='改变边框色',
# 该按钮触发change_outline函数
command=change_outline)
outlinebn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
movebn = Button(bottomF, text='右下移动',
# 调用move方法移动图形项
command=lambda : canvas.move(oval, 15, 10))
movebn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
coordsbn = Button(bottomF, text='位置复位',
# 调用coords方法重设图形项的大小和位置
command=lambda : canvas.coords(oval, 180, 50, 380, 180))
coordsbn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
# 再次添加Frame容器
bottomF = Frame(window)
bottomF.pack(fill=X,expand=True)
zoomoutbn = Button(bottomF, text='缩小',
# 调用scale方法对图形项进行缩放
# 前面两个坐标指定缩放中心,后面两个参数指定横向、纵向的缩放比
command=lambda : canvas.scale(oval, 180, 50, 0.8, 0.8))
zoomoutbn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
zoominbn = Button(bottomF, text='放大',
# 调用scale方法对图形项进行缩放
# 前面两个坐标指定缩放中心,后面两个参数指定横向、纵向的缩放比
command=lambda : canvas.scale(oval, 180, 50, 1.2, 1.2))
zoominbn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
def select_handler(ct):
global current, current_outline, current_width
# 如果ct元组包含了选中项
if ct is not None and len(ct) > 0:
ct = ct[0]
# 如果current对应的图形项不为空
if current is not None:
# 恢复current对应的图形项的边框
canvas.itemconfig(current, outline=current_outline,
width = current_width)
# 获取当前选中图形项的边框信息
current_outline = canvas.itemcget(ct, 'outline')
current_width = canvas.itemcget(ct, 'width')
# 使用current保存当前选中项
current = ct
def click_handler(event):
# 获取当前选中的图形项
ct = canvas.find_closest(event.x, event.y)
# 调用select _handler处理选中图形项
select_handler(ct)
def click_select():
# 取消为“框选”绑定的两个事件处理函数
canvas.unbind('<B1-Motion>')
canvas.unbind('<ButtonRelease-1>')
# 为“点选”绑定鼠标点击的事件处理函数
canvas.bind('<Button-1>', click_handler)
clickbn = Button(bottomF, text='点选图形项',
# 该按钮触发click_select函数
command=click_select)
clickbn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
# 记录鼠标拖动的第一个点的x、y坐标
firstx = firsty = None
# 记录前一次绘制的、代表选择区的虚线框
prev_select = None
def drag_handler(event):
global firstx, firsty, prev_select
# 刚开始拖动时,用鼠标位置为firstx、firsty赋值
if firstx is None and firsty is None:
firstx, firsty = event.x, event.y
leftx, lefty = min(firstx, event.x), min(firsty, event.y)
rightx, righty = max(firstx, event.x), max(firsty, event.y)
# 删除上一次绘制的虚线选择框
if prev_select is not None:
canvas.delete(prev_select)
# 重新绘制虚线选择框
prev_select = canvas.create_rectangle(leftx, lefty, rightx, righty,
dash=2)
def release_handler(event):
global firstx, firsty
if prev_select is not None:
canvas.delete(prev_select)
if firstx is not None and firsty is not None:
leftx, lefty = min(firstx, event.x), min(firsty, event.y)
rightx, righty = max(firstx, event.x), max(firsty, event.y)
firstx = firsty = None
# 获取当前选中的图形项
ct = canvas.find_enclosed(leftx, lefty, rightx, righty)
# 调用select _handler处理选中图形项
select_handler(ct)
def rect_select():
# 取消为“点选”绑定的事件处理函数
canvas.unbind('<Button-1>')
# 为“框选”绑定鼠标拖动、鼠标释放的事件处理函数
canvas.bind('<B1-Motion>', drag_handler)
canvas.bind('<ButtonRelease-1>', release_handler)
rectbn = Button(bottomF, text='框选图形项',
# 该按钮触发rect_select函数
command=rect_select)
rectbn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
deletebn = Button(bottomF, text='删除',
# 删除图形项
command=lambda : canvas.delete(oval))
deletebn.pack(side=LEFT, ipadx=10, ipady=5, padx=3)
window.mainloop()
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值