向量学习2:图形围绕自己中心旋转、围绕图形外或内任意点为中心旋转

在前边博文“向量学习1”中,介绍了在篮球游戏中,防守者逼近防守投篮者,如何用向量,计算逼近的方向以及前进的距离。方法可用篮球投篮、足球射门和射击的子弹轨迹等等方面。在pygame游戏中,可能图形围绕自己中心旋转;也可能象地球围绕太阳那样,图形围绕远处某点旋转;也可能象坦克炮那样旋转,线形图形以线端点为中心旋转。本文用例子说明用向量实现的方法。首先介绍图形围绕图形自己中心旋转。见下边代码。

p=pygame.image.load("L1.png").convert_alpha() 
rect=p.get_rect(center=(150,100))
p1=pygame.transform.rotate(p,10)	   #将p图旋转10度,返回旋转后的Surface实例
r=p1.get_rect(center=rect.center)  	   #如注释此条语句
screen.blit(p1, r)			           #同时注释此条语句
#screen.blit(p1,(150,100))             #改为此条语句,将发生抖动 

其中第3条语句将p图以p图中心点为旋转中心旋转10度,返回旋转后的Surface实例p1。请注意,每次返回的p1图的中心点可能不重合,为了使图形在原位置显示,第4条语句将p1中心点修改为p图中心点。如按照注释修改,去掉两句,增加一句,在连续旋转时,就会看到图形抖动。本例使用两个图形作为旋转对象,如下图,一条水平线,一个圆,为了看到圆转动,圆有1个突起。后边要用到,凸起和x轴夹角为0。
在这里插入图片描述
实际例子完整程序如下。

import pygame
bgcolor = pygame.Color('blue')
pygame.init()
size = width, height = 400,300
screen = pygame.display.set_mode(size)  
pygame.display.set_caption("原地旋转")
p=pygame.image.load("c.png").convert_alpha()
rect=p.get_rect(center=(150,100))
fclock = pygame.time.Clock()
fps = 10
angle=0
running = True
while running:    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False        
    screen.fill(bgcolor)
    angle+=10
    p1=pygame.transform.rotate(p, angle)                
    r=p1.get_rect(center=rect.center)     #如注释此条语句                        
    screen.blit(p1, r)                    #同时注释此条语句
    #screen.blit(p1,(150,100))            #改为此条语句,将发生抖动
    pygame.display.flip()                           
    fclock.tick(fps)
pygame.quit()

3张效果图如下。第1图旋转的图形是圆,第2图是一条水平线段,两图都没有抖动。在第3图可看到水平线段有明显抖动。从第2图可以验证是以图形中心点为旋转中心完成旋转。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果希望图形象地球绕太阳那样旋转,也就是图形旋转中心不是图形中心点,而是图形外某点,这就需要向量的概念。为了看懂下边论述,有必要解释“向量”和“有向线段”概念。数学意义上的向量,只有方向和长度,向量的位置是没有意义的。但实际上,在程序中处理的向量是在游戏坐标系中的有向线段,位置还是必要的。可以这样理解,有向线段是指定了位置的向量,因此,向量的许多概念和方法也适用于有向线段,下边论述中的向量一般是指有向线段。首先看下边两条语句。

v=pygame.math.Vector2(100,0)
v1 = v.rotate(angle)

第1条语句建立从(0,0)到(100,0)的向量v,该向量和x轴夹角为0,即向量角度为0,长度为100。第2条语句的旋转中心为(0,0),即围绕(0,0)旋转指定角度,旋转后产生新向量v1,起点不变,还是(0,0)。如果每帧中,v向量旋转某角度得到v1后,都把图形放到v1向量头部显示,连续重复这两个动作,就看到图形围绕(0,0)旋转。但问题是pygame游戏坐标,x轴向右为正,y轴向下为正,而且x和y只取正值,即只要x或y有一个为负,图形就不可见,如果围绕(0,0)旋转,只有1/4可见,其余不可见。为此,可把实际的旋转中心移动屏幕中央,例如(240,180)。具体办法是:每次v围绕(0,0)旋转指定角度后,平移v1向量起点到(240,180)为v2,把图形放到v2向量头部显示,每帧中连续重复这两个动作,就看到图形围绕(240,180)旋转了。
那么如何平移向量呢?数学上一条线段,其起点和终点x或y坐标都增加同一个值,生成新线段,例如x都加240,y加180,则这两条线段平行,也就是平移了向量。猜想平移v1到(240,180)可能程序表达式是:v2=(240,180)+v1。为此做了验证,见下图。图中r,a=v.as_polar()是得到向量v的长度r及方向即和x轴夹角。执行了v1=(240,180)+v后,向量v和v1的长度和角度都相同,只是头部终点不同,说明该表达式确实实现了平移。
在这里插入图片描述
注意,按上述方法平移后,向量起点总是(240,180)保持不变,向量终点由于旋转,总在变化。也就是说,平移后,图形围绕(240,180)点旋转。总结一下,(240,180)点是旋转中心,v向量长度100是旋转半径。一般使图形中点(center)移到向量的终点。完整程序如下,使用的图像是有凸起的圆。

import pygame
bgcolor = pygame.Color('blue')
pygame.init()
size = width, height = 480,360
screen = pygame.display.set_mode(size)  
pygame.display.set_caption("圆围绕某点旋转")
p=pygame.image.load("c.png").convert_alpha()
length=100                     #旋转半径
#length=p.get_rect().width//2                        
v=pygame.math.Vector2(length,0)#从(0,0)到(length,0)的向量,此时旋转中心为(0,0)
c=(240.0,180.0)                     #以后将要设置的旋转中心
fclock = pygame.time.Clock()
fps = 10
angle=0
running = True
while running:    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    screen.fill(bgcolor)        #背景颜色
    angle-=5                    #正数是顺时针,负数是逆时针
    p1=pygame.transform.rotate(p, -angle+180)     #使圆突出部分指向圆心
    v1 = v.rotate(angle)    #有向线段v1旋转,起点不变为(0,0),终点旋转,坐标改变
    #下句等式右侧将v1平移,x轴方向右移240,y轴方向下移180,有向线段起点为(240,180)
    a,b=c+v1      #因此旋转中心不变,终点旋转,坐标改变,(a,b)是平移后向量顶点坐标
    #v2=c+v1                #此句也正确,坐标元组+向量使向量v1平移到v2
    #r=p1.get_rect(center=(240,180)+v1)#使用此句提示将来版本可能不支持默认类型转换
    r=p1.get_rect()         #改为下边两句,将图形移到平移后向量顶点
    r.center=(int(a),int(b))        
    screen.blit(p1, r)      #在新位置显示图形
    pygame.display.flip()                           #刷新游戏场景
    fclock.tick(fps)#fps是每秒多少帧,减去程序运行时间,为实现fps,还需延迟时间
pygame.quit()
#a=v.angle_to(v1)#两个向量之间的夹角

效果图如下。
在这里插入图片描述
凸起的圆围绕(240,180)点旋转,按以上叙述,圆的凸起应该指向x轴正方向保持不变,但实际效果是这个圆的凸起总是指向圆心。这是因为有如下语句:

angle-=5        					 #angle是向量每帧旋转角度
p1=pygame.transform.rotate(p, -angle+180)     #使圆突出部分指向圆心
v1 = v.rotate(angle) 				 #向量旋转给定角度

其中第2句使图形p(即圆)旋转了一个角度,使圆突出部分指向圆心。这个角度如何得到的呢?首先向量的初始位置角度为0,同样圆的凸起和x轴夹角也为0(见最上边的图形中的圆),两者同向。在这个位置,要让圆的凸起指向圆心,必须旋转180度,如向量再旋转angle,凸起的圆也要自转(-angle+180),这样使圆的凸起总是指向圆心。
最后解决使线形图形以线端点为中心,象坦克炮那样旋转。前边提到v向量长度100是旋转半径,只要修改v向量长度等于要旋转图形宽度一半,在使线形图形水平摆放,即和x轴夹角为0即可,本程序只要把上述程序第9条语句注释去掉即可,并将程序第9条语句的图形文件名称改为线段图形名称:L1.png即可。效果图如下。
在这里插入图片描述

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值