上回说到用pygame绘制一个静止的小方块,今天将会实现通过鼠标或者键盘来控制小方块的移动
在这之前,首先我们需要考虑一个问题:
我们怎样才会认为一个物体在运动?风动,幡动还是仁者心动?
小方块在屏幕上的相对位置发生了变化,那就代表它移动了
与连续的现实世界不同的是,计算机内部的世界是离散化的,我们其实并没有真的去移动初始的小方块
而是在屏幕上不断的擦去旧的小方块,画出新位置上的小方块,玩家看起来就像它在移动一样
因此移动的实现逻辑就得到了:
在每一帧中擦去上一帧画的小方块
获取小方块当前的位置,并在这个位置画一个新的小方块
只要帧数足够多(超过视觉暂留的需求),就实现了小方块的“连续移动”
下面我们定义一个小方块的类
class Robot(object):
def __init__(self:
self.x = 120
self.y = 350
def Move(self):
self.x+=1
self.y+=1
pygame.draw.rect(screen,color1,Rect(self.x,self.y,20,20))
小方块的初始为止在(120,350),每调用一次Move,坐标就会修改,如果绘制出新的矩形,就实现了移动
我们用这个类创建一个对象
robot = Robot()
然后开始绘制屏幕
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.fill(color)#用背景色刷掉前一帧的所有图形
robot.Move()#绘制新的位置
pygame.display.flip()
这样小方块就动起来辣
再来看怎么发出移动指令来控制移动行为
1.先看通过键盘的方向键来控制移动
pygame支持键盘事件,当按键按下的时候响应KEYDOWN事件,按键弹起的时候响应KEYDOWN事件
不过我不打算直接通过键盘事件来驱动移动行为,而采用一种更简便的方法:
在每帧更新方块位置时,获取当前被按下的键盘按键,然后对坐标做对应的修改:
key_press = pygame.key.get_pressed()
if(key_press[K_LEFT]):
self.x -= 1
elif (key_press[K_RIGHT]):
self.x += 1
elif (key_press[K_UP]):
self.y -= 1
elif (key_press[K_DOWN]):
self.y += 1
完整代码可以从这里获取
2.然后是鼠标控制。(鼠标控制要复杂一点,需要根据鼠标的点击维护好移动指令的状态)
这里我们将模拟实现鼠标移动操作最多的rts游戏(星际争霸与war3)中最基础的几个鼠标操作:
a.左键框选选中目标(可以同时选中框内的多个目标)
b.有选择单位时,右键点击移动位置,则选中的单位将会向目标点移动(持续移动,直到到达目标点为止,中间不需要其他命令)
c.左键单击空地,将会取消单位选中的状态
pygame支持一些鼠标事件,他们包括MOUSEMOTION,MOUSEBUTTONUP,MOUSEBUTTONDOWN
我们可以在事件轮训中判断当前是否发生鼠标事件
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN:
#逻辑处理
由于我们是在帧触发时处理移动指令,我们需要自己记录鼠标的位置和点击状态(一组全局变量)
mouse_state = 0#0空闲,1左键按下,2右键按下
mouse_begin = [0,0]#鼠标按下时的起始位置
mouse_end = [0,0]#鼠标的当前位置
move_tar = [0,0]#鼠标右键选择的移动目标
move_click = False#是否有未处理的右键目标
check_select = False#是否需要检测框选目标
通过鼠标的按键信息,更新维护对应的状态变量:
pressed_array = pygame.mouse.get_pressed()
for index in range(len(pressed_array)):#判断鼠标按的是左中右的哪个键
if pressed_array[index]:
if index == 0:
mouse_state = 1
check_select = True
elif index == 2:
mouse_state = 2
if mouse_state > 0 :
mouse_begin = pygame.mouse.get_pos()#获取鼠标的箭头位置
有了这些信息后,我们就可以改造一下方块类,让它根据鼠标选择的位置来进行移动
class Robot(object):
def __init__(self,clo,ms):
self.dir = [0,0]
self.x = 120
self.y = 350
self.isselect = False#是否被框选中
self.color = clo#区分颜色
self.move_speed = ms#移动速度
self.tar =[0,0]#移动目标
def Move(self):
if check_select:#检测是否在左键拉出的框内
minx = min(mouse_begin[0],mouse_end[0])
maxx = max(mouse_begin[0],mouse_end[0])
miny = min(mouse_begin[1],mouse_end[1])
maxy = max(mouse_begin[1],mouse_end[1])
if(self.x >=minx and self.x <= maxx and self.y >= miny and self.y <= maxy):
self.isselect = True
else:
self.isselect = False
if move_click:#有移动指令
if self.isselect :
self.tar = move_tar
dx = self.tar[0]-self.x
dy = self.tar[1]-self.y
len=(dx*dx+dy*dy)**0.5
if(len > 0):
dx /= len
dy /= len
dx *= self.move_speed
dy *= self.move_speed
self.dir = [dx,dy]#计算移动向量
if( self.dir[0] != 0 or self.dir[1] != 0):#移动向量非0,表示需要移动更新坐标
dx = self.tar[0]-self.x
dy = self.tar[1]-self.y
len=(dx*dx+dy*dy)**0.5
if(len < 10):
self.x=self.tar[0]
self.y=self.tar[1]
self.dir = [0,0]
self.x += self.dir[0]
self.y += self.dir[1]
if True == self.isselect :
pygame.draw.rect(screen,color1,Rect(self.x,self.y,20,20))
else:
pygame.draw.rect(screen,self.color,Rect(self.x,self.y,20,20))
完整代码可以从这里获取