Pergunta

I'm trying to give a ship velocity (I'm doing the standard asteroids game thing) and it works, but my problem is that if either the x or y is decreasing, the ship will go in that direction for a very long time at a constant speed

I think it's because the self.rect.x and self.rect.y are integers, while the velx and vely are floats, but I'm not sure how to fix it.

Here's the important bit:

class Ship(pygame.sprite.Sprite):
    # ...
    def update(self):
        self.image = pygame.transform.rotate(self.template, self.rotation)
        self.rect = self.image.get_rect(center=self.rect.center)

        real_rot = math.radians(self.rotation+90)

        key = pygame.key.get_pressed()
        if key[pygame.K_a]:
            self.rotation += 3
            if self.rotation >= 360:
                self.rotation += -360
        if key[pygame.K_d]:
            self.rotation += -3
            if self.rotation < 0:
                self.rotation += 360
        if key[pygame.K_w]:
            self.velx += math.cos(real_rot)*speed
            self.vely += -math.sin(real_rot)*speed
        if key[pygame.K_s]:
            self.velx += -math.cos(real_rot)*speed
            self.vely += math.sin(real_rot)*speed

        self.rect.y += self.vely
        self.rect.x += self.velx
        print(self.rect.x, self.rect.y)

        self.velx *= 0.9
        self.vely *= 0.9
##        if abs(self.velx) < 1:
##            self.velx = 0
##        if abs(self.vely) < 1:
##            self.vely = 0

And here's the full code:

import pygame
import math

pygame.init()

screen_size = (800, 600)
ship_size = (50, 50)
line_thickness = 4
speed = 2

screen = pygame.display.set_mode(screen_size)

white, black = (255, 255, 255), (0, 0, 0)

sprites = pygame.sprite.Group()

class Ship(pygame.sprite.Sprite):
    def __init__(self):
        super(Ship, self).__init__()

        self.rotation = 0
        self.velx = 0
        self.vely = 0
        self.template = pygame.Surface((ship_size[0]+line_thickness*2, ship_size[1]+line_thickness*2))
        self.template.fill((0, 0, 127))
        pygame.draw.polygon(self.template, white, ((ship_size[0]/2+line_thickness, line_thickness), (ship_size[0]+line_thickness, ship_size[1]+line_thickness), (ship_size[0]/2+line_thickness, 0.8*ship_size[1]+line_thickness), (line_thickness, ship_size[1]+line_thickness)), line_thickness)

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

        self.rect.x, self.rect.y = screen_size[0]/2 - ship_size[0]/2, screen_size[1]/2 - ship_size[1]/2

        self.add(sprites)

    def update(self):
        self.image = pygame.transform.rotate(self.template, self.rotation)
        self.rect = self.image.get_rect(center=self.rect.center)

        real_rot = math.radians(self.rotation+90)

        key = pygame.key.get_pressed()
        if key[pygame.K_a]:
            self.rotation += 3
            if self.rotation >= 360:
                self.rotation += -360
        if key[pygame.K_d]:
            self.rotation += -3
            if self.rotation < 0:
                self.rotation += 360
        if key[pygame.K_w]:
            self.velx += math.cos(real_rot)*speed
            self.vely += -math.sin(real_rot)*speed
        if key[pygame.K_s]:
            self.velx += -math.cos(real_rot)*speed
            self.vely += math.sin(real_rot)*speed

        self.rect.y += self.vely
        self.rect.x += self.velx
        print(self.rect.x, self.rect.y)

        self.velx *= 0.9
        self.vely *= 0.9
##        if abs(self.velx) < 1:
##            self.velx = 0
##        if abs(self.vely) < 1:
##            self.vely = 0

player = Ship()

running = True
while running:
    pygame.time.Clock().tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
            running = False

    screen.fill(black)
    player.update()
    sprites.draw(screen)
    pygame.display.flip()

pygame.quit()

You'll notice that on lines 63-66 I tried something, but it wasn't really a good solution.

Foi útil?

Solução

The problem is because you're using the x and y values of the rect. Since the size of the rect will change when the ship rotates, the x and y values drift slightly/interact oddly with the rotating.

To fix it, modify your update method to look like the following:

def update(self):
    self.image = pygame.transform.rotate(self.template, self.rotation)
    self.rect = self.image.get_rect(center=self.rect.center)

    real_rot = math.radians(self.rotation+90)

    key = pygame.key.get_pressed()
    if key[pygame.K_a]:
        self.rotation += 3
        if self.rotation >= 360:
            self.rotation += -360
    if key[pygame.K_d]:
        self.rotation += -3
        if self.rotation < 0:
            self.rotation += 360
    if key[pygame.K_w]:
        self.velx += math.cos(real_rot)*speed
        self.vely += -math.sin(real_rot)*speed
    if key[pygame.K_s]:
        self.velx += -math.cos(real_rot)*speed
        self.vely += math.sin(real_rot)*speed

    self.x += self.velx
    self.y += self.vely

    self.rect.x = self.x
    self.rect.y = self.y

    self.velx *= 0.9
    self.vely *= 0.9

Now, your ship's coordinates are independent from how it's being rotated/transformed, and the two won't infringe on each other. (Currently, the ship will look a little funny as it's rotating, but it shouldn't be too difficult to work out the math to fix that).

Incidentally, you may want to consider storing the rotation and magnitude of the ship instead of the x and y velocities. A lot of your math would be simplified if you used Polar coordinates, and converted to x and y values only when you need to display things on the board.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top