用Python和Pygame写游戏-从入门到精通(9)

By | 2011/06/18

上次我们说到了向量,不得不说向量是一个伟大的发明,在单纯的数字运算之中,居然就把方向也包含其中。对于如今的我们来看,非常普通的事情,几百年前的人们能够考虑到这个,实在是非常的不容易。不过同时我们也要有这样的意识——我们现在所使用的数学,未必就是最完美的。时代发展科技进步,或许我们会有更好的方式来诠释我们的世界。想想一片叶子飘落,有它独特的轨迹,如果要人类计算出来那个轨迹,即便可能,也是无比繁杂的。叶子懂我们的数学吗?不,它不懂,但它就优雅的落了下来。自然有着我们尚无法理解的思考方式,我们现在所使用的工具,还是太复杂!人类要向“道”继续努力才行啊。

魔法禁书目录,一方通行

“一方通行”凭借向量的力量成为了学园第一能力者,我们也得好好学习向量才是

扯远了,虽然不记得学校里是什么时候开始接触到向量的,不过肯定也不会太晚,如果你不知道什么是向量,最好先找一本书看看吧,这里只会有一些最最核心的讲解。

引入向量

我们先考虑二维的向量,三维也差不多了,而游戏中的运动最多只用得到三维,更高的留给以后的游戏吧~

向量的表示和坐标很像,(10,20)对坐标而言,就是一个固定的点,然而在向量中,它意味着x方向行进10,y方向行进20,所以坐标(0,0)加上向量(10,20)后,就到达了点(10,20)。

向量可以通过两个点来计算出来,如下图,A经过向量AB到达了B,则向量AB就是(30, 35) – (10, 20) = (20, 15)。我们也能猜到向量BA会是(-20, -15),注意向量AB和向量BA,虽然长度一样,但是方向不同。

创建向量

在Python中,我们可以创建一个类来存储和获得向量(虽然向量的写法很像一个元组,但因为向量有很多种计算,必须使用类来完成):

class Vector2(object):
    def __init__(self, x=0.0, y=0.0):
        self.x = x
        self.y = y
    def __str__(self):
        return "(%s, %s)"%(self.x, self.y)

    @classmethod
    def from_points(cls, P1, P2):
        return cls( P2[0] – P1[0], P2[1] – P1[1] )
#我们可以使用下面的方法来计算两个点之间的向量
A = (10.0, 20.0)
B = (30.0, 35.0)
AB = Vector2.from_points(A, B)
print AB

原理上很简单,函数修饰符@不用我说明了吧?如果不明白的话,可以参考Python的编程指南。

向量的大小

向量的大小可以简单的理解为那根箭头的长度,勾股定理熟稔的各位立刻知道怎么计算了:

    def get_magnitude(self):
        return math.sqrt( self.x**2 + self.y**2 )

把这几句加入到刚刚的Vector2里,我们的向量类就多了计算长度的能力。嗯,别忘了一开始要引入math库。

单位向量

一开头说过,向量有着大小和方向两个要素,通过刚刚的例子,我们可以理解这两个意思了。在向量的大家族里,有一种比较特殊的向量叫“单位向量”,意思是大小为1的向量,我们还能把任意向量方向不变的缩放(体现在数字上就是x和y等比例的缩放)到一个单位向量,这叫向量的规格(正规)化,代码体现的话:

    def normalize(self):
        magnitude = self.get_magnitude()
        self.x /= magnitude
        self.y /= magnitude

使用过normalize方法以后,向量就成了一个单位向量。单位向量有什么用?我们以后会看到。

向量运算

我们观察下图,点B由A出发,通过向量AB到达,C则有B到达,通过BC到达;C直接由A出发的话,就得经由向量AC。

向量加法

由此我们得到一个显而易见的结论向量AC = 向量AB + 向量BC。向量的加法计算方法呼之欲出:

(20, 15) + (-15, 10) = (20-15, 15+10) = (5, 25)

把各个方向分别相加,我们就得到了向量的加法运算法则。很类似的,减法也是同样,把各个方向分别想减,可以自己简单验证一下。代码表示的话:

    def __add__(self, rhs):
        return Vector2(self.x + rhs.x, self.y + rhs.y)
    def __sub__(self, rhs):
        return Vector2(self.x - rhs.x, self.y - rhs.y)

两个下划线“__”为首尾的函数,在Python中一般就是重载的意思,如果不知道的话还需要稍微努力努力:)当然,功力稍深厚一点的,就会知道这里super来代替Vector2可能会更好一些,确实如此。不过这里只是示例代码,讲述一下原理而已。

有加减法,那乘除法呢?当然有!不过向量的乘除并不是发生在两个向量直接,而是用一个向量来乘/除一个数,其实际意义就是,向量的方向不变,而大小放大/缩小多少倍。如下图:
向量乘除法

    def __mul__(self, scalar):
        return Vector2(self.x * scalar, self.y * scalar)
    def __div__(self, scalar):
        return Vector2(self.x / scalar, self.y / scalar)

向量的运算被广泛的用来计算到达某个位置时的中间状态,比如我们知道一辆坦克从A到B,中间有10帧,那么很显然的,把步进向量通过(B-A)/10计算出来,每次在当前位置加上就可以了。很简单吧?

更好的向量类

我们创造的向量类已经不错了,不过毕竟只能做一些简单的运算,别人帮我们已经写好了更帅的库(早点不拿出来?写了半天…… 原理始终是我们掌握的,自己动手,印象更深),是发挥拿来主义的时候了(可以尝试使用easy_install gameobjects简单的安装起来)。如果您无法打开这个地址,文章最后可以下载。下面是一个使用的例子:

from gameobjects.vector2 import *
A = (10.0, 20.0)
B = (30.0, 35.0)
AB = Vector2.from_points(A, B)
print "Vector AB is", AB
print "AB * 2 is", AB * 2
print "AB / 2 is", AB / 2
print "AB + (–10, 5) is", AB + (–10, 5)
print "Magnitude of AB is", AB.get_magnitude()
print "AB normalized is", AB.get_normalized()

# 结果是下面
Vector AB is ( 20, 15 )
AB * 2 is ( 40, 30 )
AB / 2 is ( 10, 7.5 )
AB + (-10, 5) is ( 10, 20 )
Magnitude of AB is 25.0
AB normalized is ( 0.8, 0.6 )

使用向量的游戏动画

终于可以实干一番了!这个例子比我们以前写的都要帅的多,小鱼不停的在我们的鼠标周围游动,若即若离:

background_image_filename = 'sushiplate.jpg'
sprite_image_filename = 'fugu.png'

import pygame
from pygame.locals import *
from sys import exit
from gameobjects.vector2 import Vector2

pygame.init()

screen = pygame.display.set_mode((640, 480), 0, 32)

background = pygame.image.load(background_image_filename).convert()
sprite = pygame.image.load(sprite_image_filename).convert_alpha()

clock = pygame.time.Clock()

position = Vector2(100.0, 100.0)
heading = Vector2()

while True:

    for event in pygame.event.get():
        if event.type == QUIT:
            exit()

    screen.blit(background, (0,0))
    screen.blit(sprite, position)

    time_passed = clock.tick()
    time_passed_seconds = time_passed / 1000.0

    # 参数前面加*意味着把列表或元组展开
    destination = Vector2( *pygame.mouse.get_pos() ) - Vector2( *sprite.get_size() )/2
    # 计算鱼儿当前位置到鼠标位置的向量
    vector_to_mouse = Vector2.from_points(position, destination)
    # 向量规格化
    vector_to_mouse.normalize()

    # 这个heading可以看做是鱼的速度,但是由于这样的运算,鱼的速度就不断改变了
    # 在没有到达鼠标时,加速运动,超过以后则减速。因而鱼会在鼠标附近晃动。
    heading = heading + (vector_to_mouse * .6)    

    position += heading * time_passed_seconds
    pygame.display.update()

虽然这个例子里的计算有些让人看不明白,但是很明显heading的计算是关键,如此复杂的运动,使用向量居然两句话就搞定了~看来没有白学。

动画总结

  • 正如上一章所说,所谓动画,不过是在每一帧上,相对前一帧把精灵的坐标在加减一些而已;
  • 使用时间来计算加减的量以在不同性能的计算机上获得一致的动画效果;
  • 使用向量来计算运动的过程来减轻我们的劳动,在3D的情况下,简单的使用Vector3便可以了。

如今我们已经学习到了游戏动画制作的精髓,一旦可以动起来,就能创造无数让人叹为观止的效果,是不是应该写个程序在朋友们面前炫耀炫耀了?
在下面,我们要学习接受输入和游戏里的物体互动起来。

gameobjects-0.0.3.win32.exe可运行的安装文件
gameobjects-0.0.3源码

这个gameobject开发自2010年,还是Python2.x的语法,如果您想要在Python3.x上运行,得自己修改源码了……

另外有个热心朋友找到了一个新的库,在Python3.x下可用(需要将normalize()修改为normalized()),多谢各位!

>> 用Python和Pygame写游戏-从入门到精通(10)

122 thoughts on “用Python和Pygame写游戏-从入门到精通(9)

  1. tangly

    可以尝试使用easy_install gameobjects简单的安装起来

    pygame中没有自带的向量模块吗?的自己去下载 !!!

    Reply
  2. tangly

    windows有比较成熟的2d,3d向量库呢 能否介绍一下 谢谢

    Reply
  3. xishui Post author

    @tangly: “更帅的库”的链接就是下载地址。pygame毕竟不是一个面面俱到的游戏引擎,只能把这种计算交给别人了。

    Reply
    1. wps

      博主这个链接用不了可以提供其他的地址吗?

      Reply
  4. xishui Post author

    @tangly: 汗……http://code.google.com/p/gameobjects/,文中已经给出地址了,搜索“更帅的库”,我是不是该把链接颜色改一下。。

    Reply
  5. laoma

    更帅的库有中文文档说明吗? 楼主

    Reply
  6. wei

    更帅的库提供的资源安装后,from 导入的时候提示gameobjects里有很多错误啊,还有其他的资源吗?

    Reply
  7. wei

    你好,最下边那个程序其实有很多错误,不知你发现没?

    Reply
    1. xishui Post author

      您好,不知错误是指?
      这里,提供的代码都是实际写好测试过才放上来的,不能说没有bug,但至少是可以运行的,一般条件下也工作的很好。
      加上您说gameobjects里都有错误,这很难想象,毕竟一个开发的库有那么多人使用过了,请确认自己的环境配置是否有误。

      Reply
      1. AnnieW

        File “C:/Users/Annie/PycharmProjects/test2/test15.py”, line 27
        screen.blit(background,(0, 0))
        ^
        IndentationError: unindent does not match any outer indentation level
        居然缩进有误,不能理解。

        Reply
  8. wei

    @xishui: 原来是版本的问题,支持到2.5,抱歉啊!我的是3.2的,该怎么办啊?

    Reply
    1. xishui Post author

      安装了2.X咯,不一定要2.5,我2.6运行的很好,2.7应该也没问题。至于如何安装2.X以及如何与3.X共存,不是我们这里主题,只好请你自己研究了……

      Reply
    1. xishui Post author

      I am afraid… 你可以写一个贡献出来啊:) 世界会感谢你的~~

      Reply
  9. wei

    @xishui: 没事了,谢了,今天在http://pygame.org/wiki/3DVectorClass?parent=2DVectorClass上看到了,你瞧下!

    Reply
  10. simading

    position是个点呢?还是一个向量?没看明白。

    position=Vector2(100.0,100.0)
    定义position为一个向量

    vector_to_mouse = Vector2.from_points(position, destination)
    显然这里的position代表的是点呀

    望解答!

    Reply
    1. xishui Post author

      您可以不把点和向量分开看,当确定原点是起点后,那么一个向量就对应了唯一的一个点。

      Reply
  11. kamon

    __add__函数有错
    应该是
    def __add__(self,rhs):
    return Vector2(self.x + rhs[0],self.x + rhs[1])

    Reply
  12. kamon

    @kamon: 或者测试那个地方不应该是AB + (-10,5),而是AB + Vector2(-10,5)

    Reply
    1. xishui Post author

      可不要小看了game objects,这可不是我们写的简陋向量类,亲自尝试一下看看?

      Reply
  13. kamon

    @xishui: 我就是照你写的运行,发现AB + (-10,5)那过不了,总提示没有属性x,检查半天才看到这个。还有最后一个demo运行到 screen.blit(sprite, position)这里出错。

    Reply
    1. xishui Post author

      那基本我可以肯定,阁下没有使用gameobjects。所有的demo例程,都是从运行良好的py文件中复制出来的,不可能出现这样的bug,请详细确认吧……或者,您使用的python 3.X?那样大概不行,需要自己改写下了。

      Reply
  14. 小杰

    怎么画完后有图片没有被刷新呢,有残影存在啊,最后一个代码

    Reply
  15. unoyx

    ”功力稍深厚一点的,就会知道这里super来代替Vector2可能会更好一些,确实如此。“
    这句何解?返回一个父类的对象会优于返回一个当前类的对象么?

    Reply
    1. xliu

      修改类名是,不需要逐一修改。避免硬编码。

      Reply
  16. python learner

    能不能让一个区域内的所有物体一起运动而不是单一的一个图片呢?比如说一个大矩形内部有很多小矩形,如何让小矩形随着大矩形一起运动?

    Reply
  17. zhengxiawu

    @wei: 3.x的语法甚至都和2.x有出入,现在谷歌也好,其他大公司也好都用2.x所以别学3.X了

    Reply
  18. zhoushu

    这程序越到后面鱼的速度越快 范围也越来越大了

    Reply
  19. LiuSXwww

    @zhoushu:
    heading = heading*0.999 + (vector_to_mouse * .6)
    加上一个衰减应该就会好多了,这样不会越飞越远
    如果觉得运动太慢,可以把0.6改大,或者0.999再加一个9

    Reply
  20. xumaomao

    对于小鱼会越飞越远的问题:因为vector_to_mouse是动态计算的,即移动鼠标远离小鱼的话vector_to_mouse也变大,此时不论是否对vector_to_mouse做标准化(normalize),小鱼的运动都是由原来的一个位置(position)向新的一个position移动(position += heading * time_passed_seconds),这段距离随着鼠标的移动可以变大。
    如果用@LiuSXwww的方法加上衰减,小鱼很快就不再运动了。
    如果要小鱼跟随鼠标做一个类似的椭圆轨迹的运动,就要先给小鱼加上一个向量,这个向量就是鼠标移动的向量。
    贴上我试验的一段代码供大家参考:(注,从第2行起,即m_position1=pygame.mouse.get_pos()那句开始修改博主的代码,以上与原来的相同)

    clock=pygame.time.Clock()
    #--------------------------------------
    m_position1=pygame.mouse.get_pos()
    
    desti=Vector2(*pygame.mouse.get_pos())-Vector2(*sprite.get_size())/2.
    position=desti-(50,50)
    
    vector_to_mouse=Vector2.from_points(position,desti)
    vector_normal=Vector2(-vector_to_mouse[1],vector_to_mouse[0])
    vector_normal.normalize()
    
    heading=vector_normal
    
    while True:
        for event in pygame.event.get():
            if event.type==QUIT:
                exit()
    
        screen.blit(background,(0,0))
        screen.blit(sprite,position)
        time_passed=clock.tick()/1000.
    
        m_position2=pygame.mouse.get_pos()
        v1=Vector2.from_points(m_position1,m_position2)
        position=position+v1
        desti=m_position2-Vector2(*sprite.get_size())/2.
    
        vector_to_mouse=Vector2.from_points(position,desti)
        vector_to_mouse.normalize()
        heading=heading+vector_to_mouse
        position+=heading*time_passed
    
        m_position1=m_position2
    
        pygame.display.update()
    Reply
    1. yang123

      虽然我没有调试出来,但这个想法必须点赞

      Reply
    2. taylor

      可以的,不过好像只会沿一个斜率方向 来回运动了

      Reply
  21. zhang

    @wei:我也是这个问题,请问你是怎么解决的呢?python3.2导入gameobjects提示错误信息如下:
    Traceback (most recent call last):
    File “D:/Program Files/Python3.2.3/script/pygame14”, line 7, in
    from gameobjects.vector2 import Vector2
    File “D:Program FilesPython3.2.3libsite-packagesgameobjectsvector2.py”, line 134
    raise IndexError, “There are 2 values in this object, index should be 0 or 1”

    Reply
    1. 次第阑珊

      raise 语法到python3后变为raise ErrorName(“errorinfo”)
      找到你D盘下的源文件修改一下,或者在gameobjects的安装包里修改下,重新安装。
      推荐一个地址【python2.7和 python3.4的区别】http://www.tuicool.com/articles/3YZjquA

      Reply
  22. zhang

    @wei:
    “没事了,谢了,今天在http://pygame.org/wiki/3DVectorClass?parent=2DVectorClass上看到了,你瞧下!”
    没看懂啊

    Reply
  23. 拘束

    @xishui: 我要说的是…总是有加号啊,减号啊,等于号啊,大于号啊,小于号啊被变成奇怪的字符。复制后(虽然你不支持复制)还要手动去改。有时候改着改着就 错了…

    Reply
  24. boiler

    你好有个问题问一下。可能是python的类型转换
    18行 position = Vector2(100.0, 100.0) 这是个向量
    28行 screen.blit(sprite, position),这里blit的第二个参数应该是 个元组吧。看vector2的源代码,也查不到是哪里进行了类型的转换。python玩的还不熟,望解答。多谢 。

    Reply
    1. xumaomao

      Wo shu bu liao Chinese!!! sh*t…
      I guess it is to do with the pygame.Surface.blit() method rather than Vector2().
      My assumption is that Surface.blit() will try to interpret the 2nd argument (“position” in this case) as a tuple-like object (e.g. tuple, list or numpy.array), maybe in the following manner:
      aa=tuple(Vector2(10,10))
      “aa” is now a tuple.
      Similarly, bb=tuple([10,10]) is also a tuple.
      Just my guess though.

      Reply
      1. hxh

        对啊,楼主把这个类型转换说明一下呗,我是想不通,它是怎么转的?

        Reply
  25. 王杨

    我的出现一个错误:
    screen.blit(sprite,position)
    TypeError: invalid destination position for blit
    帮我看看啊,楼主

    Reply
    1. xishui Post author

      你把position打印出来看看呢,应该是有什么问题了。

      Reply
      1. 若累浅笑

        打印出来是个左边的格式(100, 100)

        Reply
  26. taevas

    gameobjects 有64位的么?easy_install 安装用不了,每次超时

    Reply
    1. taevas

      = =没事了.原来安装用python setup.py install

      Reply
  27. canto98

    接触pygame没多久,有好多不懂,请问如果想让小鱼围着光标做椭圆运动,并且慢慢停在光标上应该怎么做?

    Reply
  28. 赵铭

    博主写的太好了!
    问个问题:那个gameobjects的库链接无法下载,博主能提供另外的地址吗。。。

    Reply
          1. odayou

            完全可用 不过在vector2.py中导入util提示模块不存在, 我是加了搜索路劲才正常。
            但是作为一个完整的包为什么会出现这个问题?

          2. odayou

            忘了说,我是python 3.4
            gameobjects安装后目录在pythonpath/Lib/site-packages/gameobjects

          3. LLL

            请问提示这个错误怎么解决ModuleNotFoundError: No module named ‘gameobjects.vector2’; ‘gameobjects’ is not a package

      1. dairenyihao

        兄台 这个问题你是怎么解决的?求指导!

        Reply
      2. dairenyihao

        兄台 这个问题你是怎么解决的,能告诉我吗?求指导!

        Reply
  29. L_MIN

    我被作者萌到了~~~(•‾̑⌣‾̑•)✧˖°

    Reply
  30. yang123

    默默的问个可能很简单的问题
    def from_points(cls, P1, P2):
    return cls( P2[0] – P1[0], P2[1] – P1[1] )
    为什么参数是cls,不是self

    Reply
  31. yang123

    在纸上画了半天的向量图总算把运动轨迹搞明白了点。随着鼠标远离小鱼,小鱼运动范围夸大确实是个问题。不管了,头都快炸了

    Reply
    1. chenlujjj

      直接使用 是啥意思、?怎么用啊?求解答

      Reply
  32. cedar

    小白请教博主,特地在 win64 位下安装了 32bit 的 python2.7 版本,不过这一节的 game objects 貌似找不到 64bit 的版本,用easy_install 也无法解决,是需要下载源码自己编译吗?

    Reply
    1. cedar

      亲测 64bit 机器可以下载 gameobjects 的源码自行编译,按照源码里边readme 的说明,打开CMD进入源文件目录执行 python setup.py install 就可以愉快地使用gameobjects了

      Reply
      1. roselily

        您好,我的也是64位的,看到下载地址时32位的,看到你也是这个问题并且已经弄好了,我想问是下载了32位的然后再安装的吗?可以用吗?

        Reply
  33. chenlujjj

    python3的咋办呢? 提供的那个东西不会用额

    Reply
    1. Alex

      博主提供的‘gameobjects-0.0.3.win32.exe可运行的安装文件’下载安装后Python3是可用的,知识需要修改一点源代码,打开D:\Python35\Lib\site-packages\gameobjects\vector2.py 修改
      第2行from util import format_number 为:from gameobjects.util import format_number
      第132,142,144行修改为 raise IndexError (“There are 2 values in this object, index should be 0 or 1”)
      raise IndexError(“There are 2 values in this object, index should be 0 or 1!”)
      raise TypeError(“Must be a number”)
      第232行修改为def __truediv__(self, rhs):

      Reply
      1. chenlujjj

        非常感谢 ~
        请问最后一个改成truediv是什么意思呢?

        Reply
        1. longlongman

          py3把除法的特殊方法名改成了__truediv__,而不是__div__

          Reply
      2. 白玉苦瓜

        大哥 我用了你的方法还是不行啊 源码vector2和论坛的这个程序运行都报错 SyntaxError: invalid syntax

        Reply
      3. 白玉苦瓜

        大哥 我用了你的方法还是不行啊 源码vector2程序运行347行报错
        File “D:\python\gameobjects-0.0.3.win32.exe_\gameobjects-0.0.3\gameobjects-0.0.3\gameobjects\vector2.py”, line 347
        print v1(‘yx’)
        ^
        SyntaxError: invalid syntax

        Reply
        1. 一个撞运气的傻小白

          用python 3.x
          print的语法应该是 print()
          把print v1(‘yx’) 改成 print(v1(‘yx’))

          Reply
  34. 山中的白胡子哥

    小鱼确实若即若离了,但是当鼠标快速移动的时候,小鱼游离的半径也会随之增大,应该是让小鱼慢慢的自己规定在某个范围之内,而不是范围越来越大。

    Reply
  35. 乐子大了

    请问 gameobjects 有64位的么?
    找到的都是32位的,无法安装,从这节后面所有的脚本,都会遇到关于向量的问题了。。哈哈

    Reply
  36. Pingback: 用Python和Pygame写游戏-从入门到精通(9)-演道网

  37. GROTHEN

    pygame.math.Vector2 不好吗?干嘛要用gameobjects

    Reply
  38. 忧桑的小兔子

    无优先级的程序
    #!/usr/bin/python
    # -*- coding: utf-8 -*-

    from sys import exit
    import pygame
    from gameobjects.vector2 import Vector2
    “””
    pygame.key.get_pressed() 获得所有按下的键值,返回一个元组,这个元组的索引就是键值,对应的就是是否按下
    key.get_focused() 返回当前的pygame窗口是否激活
    key.get_mods() 按下的组合键(Alt, Ctrl, Shift)
    key.set_mods() 模拟按下组合键的效果(KMOD_ALT, KMOD_CTRL, KMOD_SHIFT)
    key.set_repeat() 无参数调用设置pygame不产生重复按键事件,二参数(delay, interval)调用设置重复事件发生的时间
    key.name() 接受键值返回键名

    “””
    bg_file = “pic/1_1.jpg”
    fish_file = “pic/1_2.png”

    def test():
    pygame.init()
    # 创建一个窗口, 返回的是一个Surface对象
    screen = pygame.display.set_mode((500, 500))
    # 设置标题
    pygame.display.set_caption(“hello”)
    times = 0
    while True:
    event = pygame.event.poll()
    if event.type == pygame.QUIT:
    pygame.quit()
    exit()
    if pygame.key.get_pressed()[ord(” “)]:
    print “space press”,times
    times += 1
    # print pygame.key.get_focused()
    # print pygame.key.get_mods()
    # print pygame.key.set_repeat()
    # print pygame.key.name(97)

    def test1():
    pygame.init()
    background = pygame.image.load(bg_file)
    sprite = pygame.image.load(fish_file)
    sprite_speed = 300
    # 创建一个窗口, 返回的是一个Surface对象
    screen = pygame.display.set_mode((500, 500))
    # 设置标题
    pygame.display.set_caption(“hello”)
    clock = pygame.time.Clock()
    sprite_pos = (Vector2(*screen.get_size()) – Vector2(*sprite.get_size()))/2
    while True:
    event = pygame.event.poll()
    if event.type == pygame.QUIT:
    exit()
    pressed_keys = pygame.key.get_pressed()
    key_direction = Vector2(0, 0)
    if pressed_keys[pygame.K_LEFT]:
    key_direction.x -=1
    if pressed_keys[pygame.K_RIGHT]:
    key_direction.x += 1
    if pressed_keys[pygame.K_UP]:
    key_direction.y -= 1
    if pressed_keys[pygame.K_DOWN]:
    key_direction.y += 1
    # 通过向量控制方向
    key_direction.normalize()
    time_passed = clock.tick()
    time_passed_seconds = time_passed / 1000.0
    # 方向乘以 v * t,可得出移动后的位置
    sprite_pos += key_direction * sprite_speed * time_passed_seconds
    if sprite_pos.x screen.get_width() – sprite.get_width():
    sprite_pos.x = screen.get_width() – sprite.get_width()
    if sprite_pos.y screen.get_height() – sprite.get_height():
    sprite_pos.y = screen.get_height() – sprite.get_height()

    screen.blit(background, (0, 0))
    screen.blit(sprite, sprite_pos)
    pygame.display.update()

    if __name__ == “__main__”:
    test1()

    Reply
  39. 忧桑的小兔子

    def test1():
    pygame.init()
    background = pygame.image.load(bg_file)
    sprite = pygame.image.load(fish_file)
    sprite_speed = 300
    # 创建一个窗口, 返回的是一个Surface对象
    screen = pygame.display.set_mode((500, 500))
    # 设置标题
    pygame.display.set_caption(“hello”)
    clock = pygame.time.Clock()
    sprite_pos = (Vector2(*screen.get_size()) – Vector2(*sprite.get_size()))/2
    while True:
    event = pygame.event.poll()
    if event.type == pygame.QUIT:
    exit()
    pressed_keys = pygame.key.get_pressed()
    key_direction = Vector2(0, 0)
    if pressed_keys[pygame.K_LEFT]:
    key_direction.x -=1
    if pressed_keys[pygame.K_RIGHT]:
    key_direction.x += 1
    if pressed_keys[pygame.K_UP]:
    key_direction.y -= 1
    if pressed_keys[pygame.K_DOWN]:
    key_direction.y += 1
    # 通过向量控制方向
    key_direction.normalize()
    time_passed = clock.tick()
    time_passed_seconds = time_passed / 1000.0
    # 方向乘以 v * t,可得出移动后的位置
    sprite_pos += key_direction * sprite_speed * time_passed_seconds
    if sprite_pos.x screen.get_width() – sprite.get_width():
    sprite_pos.x = screen.get_width() – sprite.get_width()
    if sprite_pos.y screen.get_height() – sprite.get_height():
    sprite_pos.y = screen.get_height() – sprite.get_height()

    screen.blit(background, (0, 0))
    screen.blit(sprite, sprite_pos)
    pygame.display.update()

    Reply
  40. 忧桑的小兔子

    代码贴出来是错的,这里是修改的重点
    event = pygame.event.poll()
    pressed_keys = pygame.key.get_pressed()
    key_direction = Vector2(0, 0)
    if pressed_keys[pygame.K_LEFT]: key_direction.x -=1
    if pressed_keys[pygame.K_RIGHT]: key_direction.x += 1
    if pressed_keys[pygame.K_UP]: key_direction.y -= 1
    if pressed_keys[pygame.K_DOWN]: key_direction.y += 1

    Reply
  41. xzm2017

    标准化没有返回值,修改为如下就可以了
    def normalize(self):
    magnitude = self.get_magnitude()
    self.x /= magnitude
    self.y /= magnitude
    return (self.x,self.y)

    Reply
  42. 乾尹

    Traceback (most recent call last):
    File “D:/pycharm/filetem/game9.1.py”, line 35, in
    destination=Vector2(*pygame.mouse.get_pos())-Vector2(*sprite.get_size())
    TypeError: unsupported operand type(s) for -: ‘Vector2’ and ‘Vector2’
    …这个是什么问题啊?

    Reply
    1. 乾尹

      不好意思,弄错了一个地方,在我的vector2里面没有定义好sub和div。。。。

      Reply
  43. juyin

    destination = Vector2( *pygame.mouse.get_pos()) – Vector2( *sprite.get_size())/2
    TypeError: unsupported operand type(s) for /: ‘Vector2’ and ‘int’

    Reply
    1. longlongman

      D:\Python35\Lib\site-packages\gameobjects\vector2.py 修改第232行修改为def __truediv__(self, rhs):

      Reply
  44. mosey

    请问还有人嘛,我安装完了提示“No module named ‘gameobjects’”,不知道哪里出了错啊,还有那个新的库怎么用啊。。。百度gameobjects的资料好少,有没有别的什么方法可以代替嘛。。。。。

    Reply
  45. mosey

    解决了,下的文章提供的资源,因为用的Python3x,所以安装的时候会报错,自己把相关的源码改成Python3的语法,然后在源文件目录下,用python setup.py installa 命令安装,但是很奇怪安装完后,pycharm中配置不成功,今天重新打开时,重新配置了一下gameobjects就出来了,然后就能用了

    Reply
  46. NiceHxf

    那个,今年是2018年,我是用pycharm,Python3.6,我发现可以用Vector2D这个组件,大概功能都差不多,,,(老师写的真心好,谢谢老师)

    Reply
  47. NiceHxf

    这个Vector2D目前发现有几个地方有问题,大家还是自己改改吧,唉

    Reply
  48. bulabuka

    我是3.7 win64版本的 把楼主给的32位的安装完之后再把楼主下面给的 新的库 代替pythonpath/Lib/site-packages/gameobjects/vector2里面的内容然后根据vector2里面的修改 大致有 把Vector2改成Vec2d再把normalize改成normalized

    Reply
  49. bulabuka

    还有,我发现了一个问题,不知道这个网站是博主自己写的还是别人抄的博主的https://blog.csdn.net/u013369593/article/details/46641051

    Reply
  50. 星空

    destination = Vector2(*pygame.mouse.get_pos()) – Vector2(*sprite.get_size()) / 2
    这个不太明白,为什么需要减去精灵的大小除以二,直接用当前鼠标位置不可以吗,能解释一下吗?感谢

    Reply
    1. 烧酒

      请问你解决了吗?我也是这个问题

      Reply
      1. bloodish

        假设鼠标位置是(x,y),这个向量运算的结果是 (x-精灵宽度/2, y-精灵高度/2)
        这样处理之后,鼠标中心所在的位置刚好是精灵移动后的中心位置.

        Reply
  51. bulabuka

    你把position(100,100)改成(0,0)并且把速度改的慢一点你就会发现鱼的初始位置是鱼左上角和窗口的左上角重合的,因此说明要是不减去精灵的大小除以二的话destination就是鼠标和精灵的左上角之间的向量,如果精灵的大小不可忽略的话这个方向是不对的

    Reply
  52. 张小厨

    format_number再 util 里边,print语法改一下3.6能跑了

    Reply
  53. LLL

    vector2最后几行里v1(‘yx’)是什么意思

    v1 = Vector2(1, 2)
    print (v1(‘yx’))
    print (Vector2.from_points((5,5), (10,10)))
    这是报错
    File “D:\Python\Pythion install\Lib\site-packages\gameobjects\vector2.py”, line 347
    print v1(‘yx’)
    ^
    SyntaxError: invalid syntax

    Reply
  54. 孤独

    我用的是Python3.6,为什么一点程序就显示“找不到MSVCR71.dill,无法继续执行代码”,这是怎么回事啊,有没有大佬帮忙解决一下!

    Reply
    1. 痞z

      我也是。然后我的360提示我下载库。你去搜一下这个库下载就行了

      Reply
  55. 白玉苦瓜

    大神,我是个小白,你说的 “热心朋友找到了一个新的库,在Python3.x下可用(需要将normalize()修改为normalized())” 我理解不了 能详细说说吗? 我是把“新的库”复制粘贴到PY文件里,存入到gameobject目录下,并将normalize()修改为normalized()。 可是还是报错啊!!!

    Reply
  56. jack_xy

    由于gameobject只支出python2.X版本……目前python3.X版本中pygame.math 中包含了vector计算的模块,里面有些函数有些变化,建议大家学习一下:
    import pygame.math
    help(Vector2)
    教程中的程序一,略微修改一下,供大家参考:
    #from gameobjects.vector2 import *
    from pygame.math import *
    A = (10,20)
    B = (30,35)
    AB =Vector2(B) – Vector2(A)
    print(“Vector AB is”,AB)
    print(“AB * 2 is “,AB*2)
    print(“AB / 2 is “,AB/2)
    print(“AB + (-10,5) is “,AB + (-10,5))
    print(“Magnitude of AB is”,AB.magnitude())
    print(“AB normalized is “,AB.normalize())

    Reply
    1. jack_xy

      程序二:
      background_image_filename = ‘sushiplate.jpg’
      sprite_image_filename = ‘fugu.png’
      background = pygame.image.load(background_image_filename).convert()
      sprite = pygame.image.load(sprite_image_filename).convert_alpha()
      #鱼的原始尺寸太大,适当缩小点
      sprite_Rect = sprite.get_rect()
      ratio = 0.2
      sprite = pygame.transform.scale(sprite,(int(sprite_Rect.width*ratio),int(sprite_Rect.height*ratio)))

      clock = pygame.time.Clock()

      position = Vector2(100.0, 100.0)
      heading = Vector2()

      while True:

      for event in pygame.event.get():
      if event.type == QUIT:
      exit()

      screen.blit(background, (0,0))
      screen.blit(sprite, position)

      time_passed = clock.tick(30)
      time_passed_seconds = time_passed / 1000.0

      # 参数前面加*意味着把列表或元组展开
      destination = Vector2( *pygame.mouse.get_pos() ) – Vector2( *sprite.get_size() )/2
      # 计算鱼儿当前位置到鼠标位置的向量
      vector_to_mouse = destination – position
      # 向量规格化
      vector_to_mouse.normalize()

      # 这个heading可以看做是鱼的速度,但是由于这样的运算,鱼的速度就不断改变了
      # 在没有到达鼠标时,加速运动,超过以后则减速。因而鱼会在鼠标附近晃动。
      heading = heading + (vector_to_mouse * 0.01)

      position += heading * time_passed_seconds
      pygame.display.update()

      Reply

发表评论

您的电子邮箱地址不会被公开。