Заставьте пули стрелять в том направлении, куда смотрит игрок - PullRequest
3 голосов
/ 06 мая 2020

Я как раз получал некоторую помощь, чтобы выяснить, как заставить моего игрока стрелять пулями, когда я понял, что они всего go (вроде как ожидал этого, но, тем не менее, имел только значение y для движения). Я не знаю, как заставить пули стрелять в направлении, в котором смотрит игрок.

У меня есть некоторое представление о том, что делать, но я просто не знаю, как это сделать ... Я думал, что мог бы как-то использовать курсор и отслеживание игрока, которые есть в этой игре, для визуализации, но я не знать, как сделать это разовым, а не постоянным. Что касается диагонального движения пули, я понятия не имею.

Код ниже (разделен на две части / файл Main.py и PlayerSprite.py):

Main:

py.init()
py.mixer.init()
screen = py.display.set_mode((WIDTH, HEIGHT))
py.display.set_caption("Dimensional Drifter")
clock = py.time.Clock()

all_sprites = py.sprite.Group()
NPCs = py.sprite.Group()
bullets = py.sprite.Group()
player = Player()
all_sprites.add(player)
for i in range(14):
    n = NPC(player)
    all_sprites.add(n)
    NPCs.add(n)
# Game loop
running = True
while running:
    # keep loop running at the right speed
    clock.tick(FPS)

    for event in py.event.get():
        # check for closing window
        if event.type == py.QUIT:
            running = False
        elif event.type == py.KEYDOWN:
            if event.key == py.K_SPACE:
                New_bullet = player.Shoot()
                all_sprites.add(New_bullet)
                bullets.add(New_bullet)

    # Update
    all_sprites.update()
    # # check if there a collision between the bullet and NPC
    hits = py.sprite.groupcollide(NPCs, bullets, True, True)
    # check if there a collision between the player and NPC
    hits = py.sprite.spritecollide(player, NPCs, True)
    if hits:
        running = False

    # updates the position of of mouse and rotates it towards the mouse position
    mouse_x, mouse_y = py.mouse.get_pos()
    player.rotate(mouse_x, mouse_y)
    # render
    screen.fill(BLACK)
    all_sprites.draw(screen)
    # flip the display
    py.display.flip()

py.quit()

PlayerSprite

import pygame as py
import math
import random

WIDTH = 800
HEIGHT = 600
FPS = 60

# define colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)


class Player(py.sprite.Sprite):
    def __init__(self):
        py.sprite.Sprite.__init__(self)
        self.image = py.Surface((40, 40), py.SRCALPHA)
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.centerx = WIDTH / 2
        self.rect.bottom = HEIGHT / 2
        self.Yspeed = 0
        self.rotatableimage = self.image

    def update(self):
        self.Xspeed = 0
        self.Yspeed = 0
        # line below allow for key press to equate to move of sprite
        keypreesed = py.key.get_pressed()
        if keypreesed[py.K_a]:
            self.Xspeed = - 11
        if keypreesed[py.K_d]:
            self.Xspeed = 11
        if keypreesed[py.K_w]:
            self.Yspeed = - 11
        if keypreesed[py.K_s]:
            self.Yspeed = 11
        self.rect.x += self.Xspeed
        self.rect.y += self.Yspeed
        # line below allow the sprite to wrap around the screen
        if self.rect.left > WIDTH:
            self.rect.right = 0
        if self.rect.right < 0:
            self.rect.left = WIDTH
        if self.rect.top > HEIGHT:
            self.rect.top = 0
        if self.rect.bottom < 0:
            self.rect.bottom = HEIGHT

    def rotate(self, mouse_x, mouse_y):
        rel_x = mouse_x - self.rect.x
        rel_y = mouse_y - self.rect.y
        angle = (180 / math.pi) * -math.atan2(rel_y, rel_x)

        self.image = py.transform.rotate(self.rotatableimage, int(angle))
        self.rect = self.image.get_rect(center=(self.rect.centerx, self.rect.centery))
        return

    def Shoot(self):
       return Bullet(self.rect.centerx, self.rect.top)



class NPC(py.sprite.Sprite):
    def __init__(self, player):
        py.sprite.Sprite.__init__(self)
        self.player = player
        self.image = py.Surface((30, 30)).convert_alpha()
        self.image.fill(RED)
        self.originalimage = self.image
        self.rect = self.image.get_rect()
        self.spawn()

    # allows of spawning from all four side of the screen and set the x, y speed and spawn position
    def spawn(self):
        self.direction = random.randrange(4)
        if self.direction == 0:
            self.rect.x = random.randrange(WIDTH - self.rect.width)
            self.rect.y = random.randrange(-100, -40)
            self.Xspeed = random.randrange(-2, 2)
            self.Yspeed = random.randrange(4, 8)
        elif self.direction == 1:
            self.rect.x = random.randrange(WIDTH - self.rect.width)
            self.rect.y = random.randrange(HEIGHT, HEIGHT + 60)
            self.Xspeed = random.randrange(-2, 2)
            self.Yspeed = -random.randrange(4, 8)
        elif self.direction == 2:
            self.rect.x = random.randrange(-100, -40)
            self.rect.y = random.randrange(HEIGHT - self.rect.height)
            self.Xspeed = random.randrange(4, 8)
            self.Yspeed = random.randrange(-2, 2)
        elif self.direction == 3:
            self.rect.x = random.randrange(WIDTH, WIDTH + 60)
            self.rect.y = random.randrange(HEIGHT - self.rect.height)
            self.Xspeed = -random.randrange(4, 8)
            self.Yspeed = random.randrange(-2, 2)

    def update(self):
        self.rect.x += self.Xspeed
        self.rect.y += self.Yspeed
        # makes it so that NPC point to wards the player as it passes from side to side
        dir_x, dir_y = self.player.rect.x - self.rect.x, self.player.rect.y - self.rect.y
        self.rot = (180 / math.pi) * math.atan2(-dir_x, -dir_y)
        self.image = py.transform.rotate(self.originalimage, self.rot)
        # Respawns the NPC when they hit an side
        if self.direction == 0:
            if self.rect.top > HEIGHT + 10:
                self.spawn()
        elif self.direction == 1:
            if self.rect.bottom < -10:
                self.spawn()
        elif self.direction == 2:
            if self.rect.left > WIDTH + 10:
                self.spawn()
        elif self.direction == 3:
            if self.rect.right < -10:
                self.spawn()


class Bullet(py.sprite.Sprite):
    def __init__(self, x, y):
        py.sprite.Sprite.__init__(self)
        self.image = py.Surface((5, 5))
        self.image.fill(YELLOW)
        self.rect = self.image.get_rect()
        self.rect.bottom = y
        self.rect.centerx = x
        self.Yspeed = -10

    def update(self):
        self.rect.y += self.Yspeed
        # kill if moved of screen
        if self.rect.bottom > HEIGHT or self.rect.top < 0:
            self.kill()
        if self.rect.right > WIDTH or self.rect.left < 0:
            self.kill()

Ответы [ 2 ]

2 голосов
/ 06 мая 2020

Добавьте 2 атрибута self.lastX и self.lastY к классу Player и измените атрибуты, когда игрок меняет направление:

class Player(py.sprite.Sprite):
    def __init__(self):
        # [...]

        self.lastX = 0
        self.lastY = -10   

    def update(self):
        # [...]
        self.rect.x += self.Xspeed
        self.rect.y += self.Yspeed

        if self.Xspeed != 0 or self.Yspeed != 0:
            self.lastX = self.Xspeed
            self.lastY = self.Yspeed  

Добавьте аргумент Xspeed ans Yspeed к класс Bullet

class Bullet(py.sprite.Sprite):
    def __init__(self, x, y, Xspeed, Yspeed):
        py.sprite.Sprite.__init__(self)
        self.image = py.Surface((5, 5))
        self.image.fill(YELLOW)
        self.rect = self.image.get_rect()
        self.rect.bottom = y
        self.rect.centerx = x
        self.Xspeed = Xspeed
        self.Yspeed = Yspeed

    def update(self):
        self.rect.x += self.Xspeed
        self.rect.y += self.Yspeed
        # [...]

Установить атрибуты при появлении пули

class Player(py.sprite.Sprite):
    # [...]

    def Shoot(self):
       return Bullet(self.rect.centerx, self.rect.centery, self.lastX, self.lastY)

В качестве альтернативы также можно установить скорость в зависимости от направления на курсор мыши .

Получить положение игрока и курсора мыши и вычислить расстояние по осям x и y ( Вектор ):

pos = self.rect.center
mpos = py.mouse.get_pos()
vx = mpos[0] - pos[0]
vy = mpos[1] - pos[1]

Если положение мыши и пуля позиции равны, что не имеет никакого смысла, поэтому пуля пропускается

if vx == 0 and vy == 0:
    return None

Конечно, этот вектор слишком длинный, если бы вы использовали его для направления (Xspeed, Yspeed ), то пуля переместится к курсору мыши за один оборот.
Далее я использую pygame.math.Vector2, потому что он предоставляет удобный метод scale_to_length, который масштабирует вектор до указанной евклидовой длины :

direction = py.math.Vector2(vx, vy)
direction.scale_to_length(10)

Теперь компоненты x и y вектора содержат компоненты x и y скорости. Поскольку компоненты являются значениями с плавающей запятой, они от round до целых значений:

return Bullet(pos[0], pos[1], round(direction.x), round(direction.y))

Метод Shoot:

class Player(py.sprite.Sprite):
    # [...]

    def Shoot(self):
        pos = self.rect.center
        mpos = py.mouse.get_pos()
        vx, vy = mpos[0] - pos[0], mpos[1] - pos[1]
        if vx == 0 and vy == 0:
            return None
        direction = py.math.Vector2(vx, vy)
        direction.scale_to_length(10) 
        return Bullet(pos[0], pos[1], round(direction.x), round(direction.y))

Обратите внимание, если вы установите пулю в зависимости от направления курсора мыши, тогда может быть полезно вызвать пулю щелчком мыши:

while running:
    # [...]

    for event in py.event.get():
        if event.type == py.QUIT:
            # [...]


        elif event.type == py.MOUSEBUTTONDOWN:
             if event.button == 1:
                New_bullet = player.Shoot()
                if New_bullet:
                    all_sprites.add(New_bullet)
                    bullets.add(New_bullet)
1 голос
/ 06 мая 2020

Вы можете использовать pygames Vector2 для перемещения в любом направлении. Вы рассчитываете угол игрока и можете использовать это.

class Player(py.sprite.Sprite):
    def __init__(self):
        ...
        self.angle = 0

    def rotate(self, mouse_x, mouse_y):
        ...
        self.angle = -angle #make negative otherwise it will be going away from mouse

    def Shoot(self):
         return Bullet(self.rect.centerx, self.rect.top, py.math.Vector2(1,0).rotate(self.angle))

затем в вашем классе маркеров получите направление и добавьте к его позиции

class Bullet(py.sprite.Sprite):
    def __init__(self, x, y, Dir):
        ...
        self.Dir = Dir

    def update(self):
        self.rect.y += self.Dir[1] * self.speed
        self.rect.x += self.Dir[0] * self.speed
        ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...