python游戏引擎ppb介绍(4)开炮:精灵的创建与移动

发射导弹,其实就是创建一个不断移动的新的精灵。

本节课讲精灵的创建和它的自动平移,介绍层的概念,并开始使用资源路径。

http://p6-tt-ipv6.byteimg.com/large/pgc-image/f8c1a42316cb4082a7f6e68455b0c6b8

发射子弹

Projectile是导弹的意思。我们建立第三个精灵类:Projectile

http://p26-tt.byteimg.com/large/pgc-image/8172633bc0754c78bba666a956f04255

Projectile.png

它的图片看起来是比较抽象的。

与前两个精灵相同,我们只需建立一个同名的类就可以默认关联这个图片,但这次我们想显式地指定图片。这是因为我们不希望所有的图片都和源代码放在一起。我们在代码目录中建立一个子目录resources,并且把所有的图片都移动到这个目录中。这样,我们就必须显式地指定精灵的图片,其实也很简单,如下:

class Projectile(ppb.Sprite):

    image = ppb.Image("resources/Projectile.png")

    speed = 6

    layer= 2

    def on_update(self, event, signal):

       self.position += self.direction * self.speed * event.time_delta

 

其中,speed=6代表导弹的飞行速度,每秒飞行6个距离单位,考虑到屏幕横宽为25个距离单位,这个速度已经比较快了。

我们看导弹的on_update函数,它根据速度(speed)和方向(direction)改变导弹的位置。仍然使用的是向量计算,让代码显得简洁而清晰。

这里的方向(direction)不是精灵的内置属性(相关的内置属性是rotation)。它和speed一样,是一个扩展属性。direction属性并没有初始值,它将在发射(创建)时指定,并保存不变。

我们注意到导弹类中还定义了一个新增的参数:层号(layer)。当精灵有重叠的时候,layer值大的精灵覆盖layer值较小的精灵。我们可以简单地理解为每个精灵在显示时是按照layer从小到大排序的,layer值小的,在屏幕中先显示;layer值大的后显示,所以会在上面。

http://p1-tt-ipv6.byteimg.com/large/dfic-imagehandler/ef8823ee-55f8-400e-848e-92d72a805cf1

鼠标点击事件

我们希望当鼠标左键点击时,发生一枚导弹。只需给Blob类新增一个响应鼠标按下的函数:

class Blob(ppb.Sprite):

    image = Animation("resources/blob_{0..6}.png", 10)

    layer= 3

    def on_mouse_motion(self, event, signal):

        p1= (event.position- self.position).normalize()

        self.rotation= 270 - p1.angle(ppb.Vector(1,0))

    # 新增的函数

    def on_button_pressed(self, event, signal):

        if event.button== ppb.buttons.Primary:

            p1= (event.position- self.position).normalize()

            p2= 90- p1.angle(ppb.Vector(1,0))

            event.scene.add(Projectile(position=self.position, direction= p1, rotation=p2))

 

on_button_pressed事件,接收鼠标按下事件。对于更精细的交互处理,我们可能还会涉及到鼠标抬起事件——严格来说按下并抬起才能称为一次点击。但在这里,按下鼠标就发射导弹,仍然是很清晰的操作逻辑,对我们没有什么影响。

鼠标按下事件的event中,包含了究竟按下的是哪个按钮的信息,保存在event.button中,一共有三种可能性:

  • ppb.buttons.Primary
  • ppb.buttons.Secondary
  • ppb.buttons.Tertiary

分别代表主键(默认为左键)、辅键(默认为右键)、第三键(默认为中间键)。这里包含了一个扩展性是,如果你机器上的设置不同,它会跟随改变。

下面的计算,又是向量计算,分别计算出导弹的转向角(rotation)和前进方向(direction)。

在这里,direction的归一化处理normalize()就是必须的,因为在导弹代码中,我们用它和速度的乘积来计算新的位置,它的模如果不是1,会干扰速度的真实值。

我们注意观察导弹的图片,它的方向是向下的,所以它的值与导弹图片的前进方向是有一个固定差距的。

event中另外包含了一个关键信息,就是场景本身。通过这个参数,可以在场景中新建一个导弹精灵,就如同在setup函数中所做的一样。

场景布局与层号的作用

def setup(scene):

    scene.add(Blob(pos=(0, -3.5)))

    for x in range(-4, 5, 2):

       scene.add(Target(layer=(x+4)/2,position=ppb.Vector(x, 3)))

 

我们在布置屏幕的时候,给每个靶子设置了不同的层号。如上代码的5个靶子,从左到右依次是0,1,2,3,4。我们会发现,导弹永远在左边两个靶子上面,永远在右边两个靶子下面,但对于中间那个层号相同的靶子,效果则是随机的,有时在上,有时在下!

所以,如果我们希望两个精灵在交叠时有一个明确的表现,最好是设置一个确定的层号。

完整代码

下次课,我们来处理导弹击中靶子后的效果。现在,看一下目前为止的完整的源代码。

我们已经将图片放在了子目录下,所以每个类都做了响应的修改。

import ppb

from ppb.features.animation import Animation



class Blob(ppb.Sprite):

    image = Animation("resources/blob_{0..6}.png", 10)

    layer= 3



    def on_button_pressed(self, event, signal):

        if event.button== ppb.buttons.Primary:

            p1= (event.position- self.position).normalize()

            p2= 90- p1.angle(ppb.Vector(1,0))

            event.scene.add(Projectile(position=self.position, direction= p1, rotation=p2))



    def on_mouse_motion(self, event, signal):

        p1= (event.position- self.position).normalize()

        self.rotation= 270 - p1.angle(ppb.Vector(1,0))



class Target(ppb.Sprite):

    image = ppb.Image("resources/Target.png")

    speed= 50

    def on_update(self, update_event, signal):

       self.rotation-=self.speed* update_event.time_delta





class Projectile(ppb.Sprite):

    size = 1

    image = ppb.Image("resources/Projectile.png")

    speed = 6

    layer= 2



    def on_update(self, event, signal):

       self.position += self.direction * self.speed * event.time_delta





def setup(scene):

    scene.add(Blob(pos=(0, -3.5)))

    for x in range(-4, 5, 2):

       scene.add(Target(layer=(x+4)/2,position=ppb.Vector(x, 3)))





ppb.run(setup=setup,resolution=(800, 600))

 

http://p9-tt-ipv6.byteimg.com/large/dfic-imagehandler/de3ac3ff-5d10-4de9-abdc-7c22d692d163

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

圣手书生肖让

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值