【问题标题】:Pygame - Shooting function with two playersPygame - 两个玩家的射击功能
【发布时间】:2017-11-03 14:36:51
【问题描述】:

我一直在开发一个游戏,其中有两个玩家 [在这种情况下只是 rects,因为它很容易绘制,并且 sprite.collide_rect 函数返回一个 bool],他们互相争斗。我想为游戏添加射击功能,但没有真正的解决方案可以在两人游戏中创建一个。

我想要做的是,当第一个玩家按空格键或第二个玩家按 f 键时,他们都射出自己类型的子弹,不会与他们发生碰撞,而是会与敌人发生碰撞,反之亦然。

有没有办法在 pygame 中做到这一点? (对不起,如果我的解释不是最好的)

这里是一些相关的代码部分

    #Sprite Config
    class Player(pygame.sprite.Sprite):

        def __init__(self, image):

            super().__init__()

             self.image = image
             self.rect = self.image.get_rect()

        def right(self, pixels):
            self.rect.x += pixels

        def left (self, pixels):
            self.rect.x -= pixels

        def up(self, pixels):
            self.rect.y -= pixels

        def down(self, pixels):
            self.rect.y += pixels

        def dashleft(self, pixels):
            self.rect.x -= pixels

        def dashright(self, pixels):
            self.rect.x += pixels


    # Collision Logic

    collision = pygame.sprite.collide_rect(Player1, Player2)

    if collision == True:
        AllSprites.remove(Player1, Player2)
        pygame.display.set_caption("They Destroyed Eachother! Space to retry")
        Player1.rect.x = BlueSpawnX
        Player1.rect.y = BlueSpawnY
        Player2.rect.x = OrangeSpawnX
        Player2.rect.y = OrangeSpawnY
        Again = True

    if Again == True and keys[pygame.K_SPACE]:
        AllSprites.add(Player1, Player2)
        pygame.display.set_caption("Circles Fight!")

    AllSprites.update()

    # Drawing
    Screen.fill(Black)
    Screen.blit(Text,
               (250 - Text.get_width() // 2, 240 - Text.get_height() // 2))
    AllSprites.draw(Screen)

    # Closing
    pygame.display.flip()
    Clock.tick(FPS)

pygame.quit()

【问题讨论】:

  • 你不能指望别人为你写游戏。到目前为止,您尝试了哪些代码来实现您想要的。给我们代码的特定部分,而不是整个游戏文件。
  • 如果您需要更多帮助,我也可以打开一个聊天室,但请先阅读或观看一些 tuts。
  • 没有教程,没有视频,只是与我正在做的事情无关的随机问题。我尽可能努力地检查了这些问题,但仍有一些我不知道的事情。我应该如何区分玩家的子弹和其他子弹?我该怎么让他们动起来?什么是游戏区?我需要帮助。
  • skrx?你还在吗?
  • 我花时间写了一个示例程序。我评论了重要部分,其余部分希望是不言自明的。顺便说一句,写@skrx 给我发送通知。

标签: python pygame


【解决方案1】:

这是一个示例,其中我存储了对播放器内部两个子弹组的引用。如果您按下开火键('f' 或空格),则会将一个子弹实例添加到玩家的子弹组和 all_sprites 组中,该组会闪烁并更新它们。

碰撞检测发生在update 方法中,我检查玩家是否与self.enemy_bullets 组的子弹发生碰撞。如果有冲突,我会减少self.health,如果是<= 0,我会调用self.kill() 从所有精灵组中删除精灵。

import pygame as pg
from pygame.math import Vector2


class Player(pg.sprite.Sprite):

    def __init__(self, pos, color, left, right, up, down, fire,
                 all_sprites, bullets, enemy_bullets):
        super().__init__()
        self.image = pg.Surface((30, 50))
        self.image.fill(color)
        self.rect = self.image.get_rect(topleft=pos)
        self.vel = Vector2(0, 0)
        self.pos = Vector2(self.rect.topleft)
        self.dt = 0.03
        self.key_left = left
        self.key_right = right
        self.key_up = up
        self.key_down = down
        self.key_fire = fire
        # Store the groups as attributes, so that you can add bullets
        # and use them for the collision detection in the update method.
        self.all_sprites = all_sprites
        self.bullets = bullets
        self.enemy_bullets = enemy_bullets
        self.fire_direction = Vector2(350, 0)
        self.health = 3

    def update(self, dt):
        self.dt = dt
        self.pos += self.vel
        self.rect.center = self.pos

        # Check if enemy bullets collide with the player, reduce
        # health and kill self if health is <= 0.
        collided_bullets = pg.sprite.spritecollide(self, self.enemy_bullets, True)
        for bullet in collided_bullets:
            self.health -= 1
            if self.health <= 0:
                self.kill()

    def handle_event(self, event):
        if event.type == pg.KEYDOWN:
            if event.key == self.key_left:
                self.vel.x = -90 * self.dt
                self.fire_direction = Vector2(-350, 0)
            elif event.key == self.key_right:
                self.vel.x = 90 * self.dt
                self.fire_direction = Vector2(350, 0)
            elif event.key == self.key_up:
                self.vel.y = -90 * self.dt
                self.fire_direction = Vector2(0, -350)
            elif event.key == self.key_down:
                self.vel.y = 90 * self.dt
                self.fire_direction = Vector2(0, 350)
            elif event.key == self.key_fire:  # Add a bullet to the groups.
                bullet = Bullet(self.rect.center, self.fire_direction)
                self.bullets.add(bullet)
                self.all_sprites.add(bullet)
        elif event.type == pg.KEYUP:
            if event.key == self.key_left and self.vel.x < 0:
                self.vel.x = 0
            elif event.key == self.key_right and self.vel.x > 0:
                self.vel.x = 0
            elif event.key == self.key_up and self.vel.y < 0:
                self.vel.y = 0
            elif event.key == self.key_down and self.vel.y > 0:
                self.vel.y = 0


class Bullet(pg.sprite.Sprite):

    def __init__(self, pos, velocity):
        super().__init__()
        self.image = pg.Surface((5, 5))
        self.image.fill(pg.Color('aquamarine1'))
        self.rect = self.image.get_rect(center=pos)
        self.pos = pos
        self.vel = velocity

    def update(self, dt):
        self.pos += self.vel * dt
        self.rect.center = self.pos


class Game:

    def __init__(self):
        self.fps = 30
        self.done = False
        self.clock = pg.time.Clock()
        self.screen = pg.display.set_mode((800, 600))
        self.bg_color = pg.Color('gray30')

        # Sprite groups that contain the players and bullets.
        self.all_sprites = pg.sprite.Group()
        self.bullets1 = pg.sprite.Group()  # Will contain bullets of player1.
        self.bullets2 = pg.sprite.Group()  # Will contain bullets of player2.
        player1 = Player(
            (100, 300), pg.Color('dodgerblue2'),
            pg.K_a, pg.K_d, pg.K_w, pg.K_s, pg.K_f,
            self.all_sprites, self.bullets1, self.bullets2)  # Pass the groups.
        player2 = Player(
            (300, 400),  pg.Color('sienna2'),
            pg.K_j, pg.K_l, pg.K_i, pg.K_k, pg.K_SPACE,
            self.all_sprites, self.bullets2, self.bullets1)  # Pass the groups.
        self.all_sprites.add(player1, player2)
        self.players = pg.sprite.Group(player1, player2)

    def run(self):
        while not self.done:
            self.dt = self.clock.tick(self.fps) / 1000
            self.handle_events()
            self.run_logic()
            self.draw()

    def handle_events(self):
        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.done = True
            for player in self.players:
                player.handle_event(event)

    def run_logic(self):
        self.all_sprites.update(self.dt)

    def draw(self):
        self.screen.fill(self.bg_color)
        self.all_sprites.draw(self.screen)
        pg.display.flip()


if __name__ == '__main__':
    pg.init()
    Game().run()
    pg.quit()

如果您想直接在事件循环中进行事件处理,可以将Playerhandle_event 方法中的代码移动到Gamehandle_event 方法中。这是一个简短的示例:

import pygame as pg
from pygame.math import Vector2


class Player(pg.sprite.Sprite):

    def __init__(self, pos, *groups):
        super().__init__(*groups)
        self.image = pg.Surface((30, 50))
        self.image.fill(pg.Color('steelblue2'))
        self.rect = self.image.get_rect(center=pos)
        self.vel = Vector2(0, 0)
        self.pos = Vector2(pos)

    def update(self):
        self.pos += self.vel
        self.rect.center = self.pos


class Bullet(pg.sprite.Sprite):

    def __init__(self, pos, velocity):
        super().__init__()
        self.image = pg.Surface((5, 5))
        self.image.fill(pg.Color('aquamarine1'))
        self.rect = self.image.get_rect(center=pos)
        self.pos = pos
        self.vel = velocity

    def update(self):
        self.pos += self.vel
        self.rect.center = self.pos


def main():
    screen = pg.display.set_mode((640, 480))
    clock = pg.time.Clock()
    all_sprites = pg.sprite.Group()
    bullets = pg.sprite.Group()
    player = Player((100, 300), all_sprites)

    done = False

    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True
            elif event.type == pg.KEYDOWN:
                if event.key == pg.K_d:
                    player.vel.x = 5
                elif event.key == pg.K_SPACE:
                    # Just create a bullet and add it to the sprite groups.
                    bullet = Bullet(player.rect.center, Vector2(8, 0))
                    bullets.add(bullet)
                    all_sprites.add(bullet)
            elif event.type == pg.KEYUP:
                if event.key == pg.K_d:
                    player.vel.x = 0

        all_sprites.update()
        screen.fill((30, 30, 30))
        all_sprites.draw(screen)

        pg.display.flip()
        clock.tick(30)


if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()

【讨论】:

  • Bullet.update 方法中,您需要添加代码以在项目符号离开屏幕时将其移除。
  • 无意冒犯,但你的编码方法与我不同(例如:我不使用游戏功能来运行大部分内容,一切都在主游戏上)文件或变量/精灵/函数文件中)我将尝试重构它,但如果我无法掌握它,也许你可以打开一个聊天。不管怎么说,还是要谢谢你。 @skrx
  • dt 表示delta time,即自上次滴答以来经过的时间。您需要它来使精灵帧速率的移动速度独立。代码源于我的一个模板,我只是在示例中保留了dt,但您可以暂时忽略它或将其删除。
  • 关于'key'属性,如果不将它们存储在播放器中,则必须在事件循环中复制大量事件处理代码。如果需要,可以将 handle_event 方法移至事件循环,您只需保留 for player in self.players: 循环以避免重复。我认为它更适合 Player 类,因为操作了这么多实例属性。
【解决方案2】:

你在正确的轨道上。 立即阅读 sprite Groups on pygame 文档的文档。

然后,为子弹本身创建另一个继承自 pygame.spite.Sprite 的类,每当一个玩家射击时,只需创建新子弹,并将其添加到“player1_shoots”组。您可以在组上调用碰撞方法,该方法将检查该组中所有精灵的碰撞,因此,通过使用这种面向对象的方法,您基本上可以免费获得玩家的多次射击。

另外,请注意,您应该在子弹类上编写一个“更新”方法,以使子弹朝正确的方向移动。然后您只需致电group.update() 即可立即更新所有项目符号。

附带说明一下,如果您愿意,请尝试使用与矩形不同的图像 - 您会注意到,对于大多数游戏的运行速度,如果根据实际图像或逐像素游戏计算碰撞,则几乎没有区别。您将需要一个非常具体的游戏,而不需要 rect-collision。当您这样做时,Pyagme 甚至会为此提供支持。

【讨论】:

  • 谢谢,但是我在 update() 函数中编码了什么?以及如何确保它们不会飞出屏幕并继续对 CPU 征税?
  • 我已经在这里回答了第二个问题:stackoverflow.com/a/47035219/6220679
  • 我尽我最大的努力将代码重构为可以工作的代码,但代码膨胀成热垃圾,我将我的代码重构为单独的文件,我会及时更新你是否可以让它工作
  • 你应该在子弹对象上有速度属性。比如说“vx”和“vy”。每次更新,您将它们添加到子弹的矩形 x 和 y 坐标。然后你检查一下,如果他们从游戏区掉下来,只需调用“self.kill()”——他们将从组中删除,不再更新。 (如果它们不在任何其他变量中,则由 Python 从内存中删除)
  • 我仍然不知道该怎么做。我在更新功能中放了什么?碰撞时如何移除子弹?如何确定哪些子弹是哪些?什么是游戏区?我不知道。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-13
  • 2021-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多