python - pygame - 如何让 Sprite 朝着它面对矢量的方向移动?

标签 python pygame

我正在制作一款小行星游戏,例如控件,向上箭头用于加速, 右箭头顺时针旋转,左箭头逆时针旋转,例如,如果我想减速,我需要将船旋转 180° 并加速。 我可以旋转,为此我画了两个矢量(速度和航向)。 我正在尝试用矢量实现这种类型的运动,但也许我不应该这样做? 这就是我的想法。

import pygame
import sys
from pygame.locals import *  # pygame.locals.QUIT --> QUIT
# Vector2
vec = pygame.math.Vector2

# initialize pygame
pygame.init()
FPS = 60  # frames per second
fps_clock = pygame.time.Clock()
# set up the window
WIDTH = 800
HEIGHT = 800
DISPLAY = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('VECTOR_2')
FONT = pygame.font.Font(None, 24)
# RGB colors
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

MAX_SPEED = 9


class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        # set ship image
        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.rect = self.image.get_rect()
        self.rect.center = (WIDTH / 2, HEIGHT / 2)
        self.position = vec(WIDTH / 2, HEIGHT / 2)
        self.vel = vec(0, 0)
        self.acceleration = vec(0, 0)
        # heading vector
        self.heading = vec(0, -1)  # upwards
        self.rect.center = self.position
        self.angle_speed = 0
        self.angle = 0

    def update(self):
        self.acceleration = vec(0, 0)
        keys = pygame.key.get_pressed()
        if keys[K_LEFT]:
            self.acceleration.x = -0.2
        if keys[K_RIGHT]:
            self.acceleration.x = 0.2

        if keys[K_UP]:
            self.acceleration.y = -0.2

        if keys[K_DOWN]:
            self.acceleration.y = 0.2

        if keys[K_a]:
            self.angle_speed = -1
            player.rotate()
        if keys[K_d]:
            self.angle_speed = 1
            player.rotate()
        # max speed
        if self.vel.length() > MAX_SPEED:
            self.vel.scale_to_length(MAX_SPEED)

        self.vel += self.acceleration
        self.position += self.vel

        self.rect.center = self.position

    def rotate(self):
        # rotate the heading vector
        self.heading.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 draw_vectors(self, screen):
        scale = 20
        # vel
        pygame.draw.line(screen, GREEN, self.position, (self.position + self.vel * scale), 5)
        # desired
        pygame.draw.line(screen, RED, self.position, (self.position + self.heading * scale), 5)

    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

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

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

    DISPLAY.fill(BLACK)
    player.wrap_around_screen()
    all_sprites.update()
    all_sprites.draw(DISPLAY)
    player.draw_vectors(DISPLAY)
    txt = FONT.render('angle {:.1f}'.format(player.angle), True, (150, 150, 170))
    DISPLAY.blit(txt, (10, 10))
    pygame.display.update()
    fps_clock.tick(FPS)

任何帮助将不胜感激

最佳答案

您可以给 self.acceleration 向量一个初始长度(在本例中为 0.2),如果玩家按下 ← 或 → 则旋转它,并且只加速(将它添加到 self .vel 向量)如果 ↑ 或 ↓ 被按下。

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)

MAX_SPEED = 9


class Player(pygame.sprite.Sprite):
    def __init__(self):
        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):
        keys = pygame.key.get_pressed()
        if keys[K_LEFT]:
            self.angle_speed = -1
            player.rotate()
        if keys[K_RIGHT]:
            self.angle_speed = 1
            player.rotate()
        # If up or down is pressed, accelerate the ship by
        # adding the acceleration to the velocity vector.
        if keys[K_UP]:
            self.vel += self.acceleration
        if keys[K_DOWN]:
            self.vel -= self.acceleration

        # 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


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

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 - 如何让 Sprite 朝着它面对矢量的方向移动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48856922/

相关文章:

python - 将范围值转换为整数

python - 完整的内置文件支持 PYGAME

javascript - 在 Django 中填充数据库值后如何为下拉列表指定特定值?

python - Unable to import 'selenium' pylint(import-error) (解决方法)

python - 使用 PIL 保存图像

python - 使用 Python 请求将附件上传到 Confluence REST API 会出现 415 和 500 错误

python - 使用 UTF-8 编码创建新的 csv

python - (索引错误: list index out of range) My for loop is giving me an error?

python - 测试 python 中列表中的内容是否存在时遇到问题

python - pygame.init() 什么时候会返回 (6,0) 以外的东西?