Перемещение спрайта к игроку в Pygame (с использованием векторов Pygame) - PullRequest
0 голосов
/ 31 декабря 2018

Я играю в игру, и оппонент должен стрелять пулями в игрока.

Я хочу, чтобы пули двигались в направлении того места, где находится игрок, когда пуля стреляет (игрок может двигатьсяно пуля движется в постоянном направлении.)

Но пуля просто мерцает на противнике.

Я использую Vector2 Pygame для управления движением пуль.

Вотпример заклинания пули:

bulletspell = Spell(
    pygame.image.load("Sprites/lightblue-glowey.png"),
    ((0, pygame.Vector2(-0.5, 1) * 4), #these vectors show the bullet shooting pattern
     (0, pygame.Vector2(0, 1) * 4),
     (0, pygame.Vector2(0.5, 1) * 4)),
    10, 8, 340
    )

Вектор, который я пробовал, был (player.image.get_rect(topleft=(player.rect.x, player.rect.y)).x, 1)

Я не ищу весь код, подлежащий пересмотру, у меня был слишкоммного ревизий и код у меня работает, мне просто нужна помощь в определении вектора.

Вот код (только для справки):

import pygame

class Player(pygame.sprite.Sprite):
    sprite = pygame.image.load("Sprites/player.png")

    def __init__(self, *groups):
        super().__init__(*groups)
        self.image = Player.sprite
        self.rect = self.image.get_rect(topleft=(445, 550))
        self.pos = pygame.Vector2(self.rect.topleft)

    def update(self):
        key = pygame.key.get_pressed()
        dist = 3
        if key[pygame.K_DOWN]:
            self.rect.y += dist
        elif key[pygame.K_UP]:
            self.rect.y -= dist
        if key[pygame.K_RIGHT]:
            self.rect.x += dist
        elif key[pygame.K_LEFT]:
            self.rect.x -= dist
class Spell:

    def __init__(self, bullet, pattern, speed, loop, tick_delay):
        self.bullet = bullet
        self.pattern = pattern
        self.speed = speed
        self.loop = loop
        self.tick_delay = tick_delay


class Opponent(pygame.sprite.Sprite):

    def __init__(self, sprite, sequence, *groups):
        super().__init__(*groups)
        self.image = sprite
        self.rect = self.image.get_rect(topleft=(425, 30))
        self.start_time = pygame.time.get_ticks()
        self.sequence = sequence
        self.spellno = 0
        self.currentspell = sequence[self.spellno]

    def update(self):
        time_gone = pygame.time.get_ticks() - self.start_time

        if self.currentspell is not None and time_gone > self.currentspell.tick_delay:
            self.start_time = pygame.time.get_ticks()
            for bullet in self.currentspell.pattern:
                if bullet[0] <= time_gone:
                    Bullet(self.rect.center, bullet[1], self.currentspell.bullet, sprites, bullets)

            self.currentspell.loop -= 1
            if self.currentspell.loop <= 0:
                self.spellno += 1
                if self.spellno >= len(self.sequence):
                    self.currentspell = None
                else:
                    self.currentspell = self.sequence[self.spellno]


class Bullet(pygame.sprite.Sprite):

    def __init__(self, pos, direction, image, *groups):
        super().__init__(*groups)
        self.image = image
        self.rect = self.image.get_rect(topleft=pos)
        self.direction = direction
        self.pos = pygame.Vector2(self.rect.topleft)

    def update(self):
        self.pos += self.direction
        self.rect.topleft = (self.pos.x, self.pos.y)
        if not screen.get_rect().colliderect(self.rect):
            self.kill()


sprites = pygame.sprite.Group()
bullets = pygame.sprite.Group()

opponentgroup = pygame.sprite.Group()


img3 = pygame.image.load("Sprites/minty.png")
player = Player(sprites)

#I tried:    
mi3 = Spell(
    pygame.image.load("Sprites/purple-glowey.png"),
    ((0, pygame.Vector2(player.image.get_rect(topleft=(player.rect.x, player.rect.y)).x, 1) * 4),
    ), 4, 8, 340)

minty_spells = [mi1, mi3]

Minty = Opponent(img3, minty_spells, opponentgroup)
sprites.add(Minty)

pygame.init()
SCREENWIDTH = 1000
SCREENHEIGHT = 650
screen = pygame.display.set_mode([SCREENWIDTH, SCREENHEIGHT])
screen.fill((255, 123, 67))
pygame.draw.rect(screen, (0, 255, 188), (50, 50, 900, 575), 0)
background = screen.copy()
clock = pygame.time.Clock()

# основной цикл идет сюда

Любая помощь будет оценена

Спасибо:)

Ответы [ 2 ]

0 голосов
/ 02 января 2019

Я рекомендую немного изменить структуру кода и превратить заклинания в подклассы Spell (взгляните на шаблон состояния ).Переместите больше кода, связанного со стрельбой, в класс Spell и задайте ему метод update, где обновляется таймер, и метод shoot, в котором создаются маркеры.

Метод shoot заклинания, которое должно быть нацелено на игрока, может быть переопределено, так что он направлен на положение игрока вместо использования одного из предопределенных направлений.

Вupdate метод Opponent, вам просто нужно проверить, выполнено ли текущее заклинание (когда loop равно 0), затем переключите заклинание, создав новый экземпляр и вызывая его метод update каждый кадр.

import pygame


class Spell:

    def __init__(self, bullet_img, speed, loop, delay):
        self.bullet_img = bullet_img
        self.pattern = None
        self.speed = speed
        self.loop = loop
        self.delay = delay
        self.start_time = pygame.time.get_ticks()

    def shoot(self, pos, target_pos):
        for pattern in self.pattern:
            Bullet(pos, pattern, self.bullet_img, sprites, bullets)

    def update(self, pos, target_pos):
        time_gone = pygame.time.get_ticks() - self.start_time
        if time_gone > self.delay:
            self.start_time = pygame.time.get_ticks()
            self.shoot(pos, target_pos)
            self.loop -= 1


class Spell1(Spell):

    def __init__(self):
        super().__init__(img, 10, 3, 340)
        self.pattern = (pygame.Vector2(-2, 4), pygame.Vector2(0, 4),
                        pygame.Vector2(2, 4))


class Spell2(Spell):

    def __init__(self):
        super().__init__(img2, 4, 2, 340)
        self.pattern = (pygame.Vector2(4, 4), pygame.Vector2(-4, 4))


class Spell3(Spell):

    def __init__(self):
        super().__init__(img3, 4, 6, 340)

    # Override the shoot method to aim at the player position.
    def shoot(self, pos, target_pos):
        direction = (pygame.Vector2(target_pos) - pos).normalize() * 4
        Bullet(pos, direction, self.bullet_img, sprites, bullets)


class Opponent(pygame.sprite.Sprite):

    def __init__(self, pos, sprite, spells, *groups):
        super().__init__(*groups)
        self.image = sprite
        self.rect = self.image.get_rect(topleft=pos)
        self.start_time = pygame.time.get_ticks()
        self.spells = spells
        self.spellno = 0
        self.currentspell = spells[self.spellno]()  # Create the instance here.

    def update(self):
        if self.spellno < len(self.spells):
            # You can pass the player position instead of the mouse pos here.
            self.currentspell.update(self.rect.center, pygame.mouse.get_pos())
            # Decrement the loop attribute of the current spell and
            # switch to the next spell when it's <= 0. When all spells
            # are done, set self.currentspell to None to stop shooting.
            if self.currentspell.loop <= 0:
                self.spellno += 1
                if self.spellno < len(self.spells):
                    self.currentspell = self.spells[self.spellno]()


class Bullet(pygame.sprite.Sprite):

    def __init__(self, pos, direction, image, *groups):
        super().__init__(*groups)
        self.image = image
        self.rect = self.image.get_rect(center=pos)
        self.direction = direction
        self.pos = pygame.Vector2(self.rect.center)

    def update(self):
        self.pos += self.direction
        self.rect.center = self.pos
        if not screen.get_rect().colliderect(self.rect):
            self.kill()


sprites = pygame.sprite.Group()
bullets = pygame.sprite.Group()
opponentgroup = pygame.sprite.Group()

img = pygame.Surface((30, 40))
img.fill((0, 100, 200))
img2 = pygame.Surface((30, 30))
img2.fill((110, 0, 220))
img3 = pygame.Surface((30, 50))
img3.fill((255, 170, 0))
minty_spells = [Spell1, Spell2, Spell3]
minty = Opponent((425, 30), img3, minty_spells, opponentgroup)
minty2 = Opponent((225, 30), img3, [Spell2, Spell3, Spell1], opponentgroup)
sprites.add(minty, minty2)

pygame.init()
screen = pygame.display.set_mode([1000, 650])
screen.fill((255, 123, 67))
pygame.draw.rect(screen, (0, 255, 188), (50, 50, 900, 575), 0)
background = screen.copy()
clock = pygame.time.Clock()


def main():
    while True:
        for events in pygame.event.get():
            if events.type == pygame.QUIT:
                pygame.quit()
                return

        sprites.update()

        screen.blit(background, (0, 0))
        sprites.draw(screen)
        pygame.display.update()

        clock.tick(100)

if __name__ == '__main__':
    main()
0 голосов
/ 31 декабря 2018

В момент создания экземпляра пули ее направление должно быть:

(Player.pos - Opponent.pos).normalise()

Это даст вам единичный вектор (вектор длины 1), указывающий от противника к игроку в тот момент, когда пуляуволена.Вам нужно будет добавить это к позиции маркера при каждом обновлении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...