pygame - 子弹精灵错误偏离船角(Vectors2)

问题描述 投票:0回答:2

当船在移动时以某些角度从船上射出子弹时,似乎有一种奇怪的偏移。此外,如果船舶向同一方向射击,那么子弹速度就会降低。我尝试使用一些SO答案,这就是我想出的:

import sys
import pygame
from pygame.locals import *
vec = pygame.math.Vector2

pygame.init()
FPS = 60
fps_clock = pygame.time.Clock()
WIDTH = 800
HEIGHT = 800
DISPLAY = pygame.display.set_mode((WIDTH, HEIGHT))
BLACK = (0, 0, 0)
BLUE = (0, 0, 255)

MAX_SPEED = 7

class Player(pygame.sprite.Sprite):
    """This class represents the Player."""

    def __init__(self):
        """Set up the player on creation."""
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((70, 50), pygame.SRCALPHA)
        pygame.draw.polygon(self.image, (50, 120, 180), ((35, 0), (0, 35), (70, 35)))
        self.original_image = self.image
        self.position = vec(WIDTH / 2, HEIGHT / 2)
        self.rect = self.image.get_rect(center=self.position)
        self.vel = vec(0, 0)
        self.acceleration = vec(0, -0.2)  # The acceleration vec points upwards.
        self.angle_speed = 0
        self.angle = 0

    def update(self):
        """Update the player's position."""
        keys = pygame.key.get_pressed()
        if keys[K_LEFT]:
            self.angle_speed = -2
            player.rotate()
        if keys[K_RIGHT]:
            self.angle_speed = 2
            player.rotate()
        # If up is pressed, accelerate the ship by
        # adding the acceleration to the velocity vector.
        if keys[K_UP]:
            self.vel += self.acceleration
        if keys[K_SPACE]:
            player.shoot()
        # max speed
        if self.vel.length() > MAX_SPEED:
            self.vel.scale_to_length(MAX_SPEED)

        self.position += self.vel
        self.rect.center = self.position

    def rotate(self):
        # rotate the acceleration vector
        self.acceleration.rotate_ip(self.angle_speed)
        self.angle += self.angle_speed
        if self.angle > 360:
            self.angle -= 360
        elif self.angle < 0:
            self.angle += 360
        self.image = pygame.transform.rotate(self.original_image, -self.angle)
        self.rect = self.image.get_rect(center=self.rect.center)

    def wrap_around_screen(self):
        """Wrap around screen."""
        if self.position.x > WIDTH:
            self.position.x = 0
        if self.position.x < 0:
            self.position.x = WIDTH
        if self.position.y <= 0:
            self.position.y = HEIGHT
        if self.position.y > HEIGHT:
            self.position.y = 0

    def shoot(self):
        # create and add missile object to the group
        missile = Missile(self.rect.center, self.acceleration, player.acceleration.as_polar()[1])
        all_sprites.add(missile)
        missiles.add(missile)


class Missile(pygame.sprite.Sprite):
    """This class represents the bullet.
     A missile launched by the player's ship.
     """

    def __init__(self, position, direction, angle):
        """Initialize missile sprite.
         Take the position, direction and angle of the player.
         """
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface([4, 10], pygame.SRCALPHA)
        self.image.fill(BLUE)
        # Rotate the image by the player.angle
        self.image = pygame.transform.rotozoom(self.image, angle, 1)
        # Pass the center of the player as the center of the bullet.rect.
        self.rect = self.image.get_rect(center=position)
        self.position = vec(position)  # The position vector.
        self.velocity = direction * 50  # Multiply by desired speed.

    def update(self):
        """Move the bullet."""
        self.position += self.velocity  # Update the position vector.
        self.rect.center = self.position  # And the rect.

        if self.rect.x < 0 or self.rect.x > WIDTH or self.rect.y < 0 or self.rect.y > HEIGHT:
            self.kill()


all_sprites = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
missiles = pygame.sprite.Group()

while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

    player.wrap_around_screen()
    all_sprites.update()

    DISPLAY.fill(BLACK)
    all_sprites.draw(DISPLAY)
    pygame.display.set_caption('angle {:.1f} accel {} accel angle {:.1f}'.format(
        player.angle, player.acceleration, player.acceleration.as_polar()[1]))
    pygame.display.update()
    fps_clock.tick(FPS)**

任何帮助,将不胜感激

python pygame
2个回答
1
投票

你几乎肯定希望你的导弹从发射船的速度开始(除了船的方向有一定的速度)。

您可以使用direction参数将Missile.__init__参数替换为velocity,该参数可以直接保存为self.velocity(没有乘法)。然后可以修改Player.shoot方法以传递适当的值,该值同时考虑船舶的方向和速度:

def shoot(self):
    # create and add missile object to the group
    missile = Missile(self.rect.center,
                      self.velocity + 50 * self.acceleration,     # new value here!
                      player.acceleration.as_polar()[1])
    all_sprites.add(missile)
    missiles.add(missile)

您可能希望使用较小倍数的船舶加速度矢量,而不是我从当前代码中复制的50,因为它不再是导弹速度的唯一组成部分。


0
投票

唯一的问题是.rotozoom使用逆时针方向的角度,而.as_polar矢量方法返回顺时针方向的角度(考虑到在过去的数学课程中学到的东西,人们可能期望.as_polar产生逆时针角度,但是Surfaces上的Y轴指向下方,而数学类通常Y指向上方)。

TL; DR:你只需要反转在rotozoom调用中传递的角度:

self.image = pygame.transform.rotozoom(self.image, -angle, 1)

您可能还想交换导弹的宽度X高度:

self.image = pygame.Surface([10, 4], pygame.SRCALPHA)
© www.soinside.com 2019 - 2024. All rights reserved.