移动矩形代码和一个非常重要的windows消息队列机制的坑

来源:互联网 发布:jquery.checktree.js 编辑:程序博客网 时间:2024/06/06 16:37
今天跟着S.Harbour的书写了第一个例程,一开始没打算一章章认真码,没想到却遇上了不少问题,收获不菲,这对接下来也是一个非常好的提醒,要脚踏实地


,不能“感觉”自己会了就不看
import pygame  
from pygame.locals import * 
import sys 
pygame.init()  #导入模块并初始化  
screen=pygame.display.set_mode((600, 500))  #创建并设置一个叫图像窗口的surface对象。名叫screen 
pygame.display.set_caption("Drawing Rectangles") 

position_x=0
position_y=0
velocity_x=1
velocity_y=2

while True:  
    for event in pygame.event.get():
        if event.type in (QUIT,KEYDOWN):
            quit()  
            sys.exit()  
            #退出的消息处理   
    screen.fill((0,0,200))        
    position_x=position_x+velocity_x
    position_y=position_y+velocity_y
 
    if position_x>500 or position_x<0:
            velocity_x=-velocity_x
    if position_y>400 or position_y<0:
            velocity_y=-velocity_y
    color=255,255,0
    position=position_x,position_y,100,100           
            
    pygame.draw.rect(screen,color,position,0)
    pygame.display.update()  
#    #刷新一下画面  

以上是结果代码。
出现在的问题主要有以下几点:
1.sys模块应该是一个内置模块,所以不import直接使用sys.exit()也不会报错。而且没有quit()只会在调试的时候崩溃,直接运行不会
2.from XXX import * 可以直接导入命名空间,但是编译器会一直warn你说某一些变量可能未定义或者定义在这个XXX里,意思是让你自己注意,自己检查检查
。这个只要无视就好。而pygame的locals官网的描述是里面定义了大量的常量。我们这里使用的QUIT和KEYDOWN就是键值常量。我尝试过用pygame.locals.QUIT
但最后会报错,所以我只能无视这个warning
3.spder编译器通过点操作有时候是看不到一个对象完整的,所有的属性和方法的。这个就很无语。只能自己翻翻手册和书才能知道,这里的display和screen里
的属性和方法就看不到。之前也出现很多这类情况
4.也是今天最重要的一点。一开始我写的程序。矩形只有在我给消息的情况下,比如移动鼠标,点击鼠标等情况下才会移动。而例程运行后却可以自动移动。后
来我发现这是因为我把绘图的程序放在了和if event.type in (QUIT,KEYDOWN):对齐的地方。当我把下面的绘图程序和for event in pygame.event.get():放对
齐的时候就可以自动运动了。这是一个很致命的错误。因为涉及到了windows处理消息的机制。windows不是实时处理消息的,一次性处理掉之前堆积起来的消息
队列,然后继续顺序执行下面的绘图和逻辑判断。在运行下面程序的同时,硬件却在实时的检测鼠标和键盘的动向,然后把这些消息放进内存的一个队列中形成
消息队列。这是一种典型的用缓冲区的方法去解决不同步的问题。等到程序运行到底部,重新再一次进入while循环后,就会又进入到处理消息队列的那个for循
环里处理消息(不然怎么会有专门的函数删除消息队列里的某个消息呢,这样就彻底理解了消息处理的机制)。所以当我把他写在for循环对齐的时候,那么当有消息时,先进入for循环,用if处理完消息后,就会跳出到下面的绘图程序。当没消息时,直接for循环就跳出了,也出来执行绘图程序。但是!当写在和if event.type in (QUIT,KEYDOWN):对齐的时候,当有消息的时候还好,他会进入for循环,判断完是不是QUIT和KEYDOWN,然后执行你的一遍绘图。但是没消息的时候。for里的event in pygame.event.get():是没有的,于是乎,程序直接跳到外面了,根本不会进去执行if event.type in (QUIT,KEYDOWN):和绘图的代码块。所以结论就是。对于有没有消息都要处理的代码,要放在for循环里面。对于有消息才执行的代码,才要放在for里面自己消息if语句对应的下面。对于有消息就执行,不在乎你是什么消息的代码,就放在for里面,if外面。因为python是没有括号只有靠对齐来区分代码的  所以要尤为注意这个问题