Перемещение спрайтов с помощью Pygame в Python - PullRequest
1 голос
/ 23 февраля 2020

Я делаю клон Астероидов, и у меня есть корабль, который плавно движется с помощью клавиш со стрелками. Корабль имеет скорость xv и yv, и для его перемещения я просто изменяю rect.x и rect.y спрайта на xv и yv соответственно. Как только я позволю go клавиш со стрелками, я бы хотел, чтобы они плавно замедлялись. Чтобы сделать это, я в настоящее время умножаю xv и yv на 0,96 каждый кадр, что одновременно замедляет корабль и обеспечивает максимальную скорость.

На первый взгляд кажется, что это работает нормально, но если присмотреться, у корабля будут странные схемы движения; например, иногда он будет немного замедляться, прежде чем перестанет двигаться вниз, но будет продолжаться с постоянной скоростью в направлении оси x. Иногда спрайт будет останавливаться или значительно замедляться по краям экрана, пока он находится в таком режиме, что не должно происходить, потому что у меня есть код на месте, так что он должен переместиться на другую сторону.

Я подозреваю, что это странное поведение связано с округлением в rect или sprite частях Pygame, но я не уверен, как это исправить. Я попытался автоматически установить скорость на ноль, как только она станет достаточно низкой, но проблема сохраняется и иногда ухудшается.

Вот мой код для класса Player:

import pygame as pg
import Settings as s
import math
class Player(pg.sprite.Sprite):
    global rect, r, xv, yv, v, track, images, pthrust

    def __init__(self, x = (s.w-30)/2, y = (s.h-45)/2, r = math.pi, xv = 0, yv = 0, v = .5):
        pg.sprite.DirtySprite.__init__(self)
        self.r = r
        self.v = v
        self.xv = xv
        self.yv = yv
        self.rect = pg.Rect(x, y, 30, 45)
        self.radius = 1
        self.images = [pg.image.load('Player.png').convert_alpha(), pg.image.load('PThrust.png').convert_alpha()]
        self.imagec = self.images[0]
        self.image = self.imagec
        self.pthrust = False

    def thrust(self): # Called every frame while up arrow is down
        self.xv += self.v*math.sin(self.r) # Accelerate the player
        self.yv += self.v*math.cos(self.r)
        self.imagec = self.images[1]
        self.pthrust = True

    def unthrust(self): # Called when up arrow is released
        self.imagec = self.images[0]
        self.pthrust = False

    def turnLeft(self): # Called every frame while left arrow is down
        self.r += math.pi/48

    def turnRight(self): # Called every frame while right arrow is down
        self.r -= math.pi/48

    def move(self): # Called every frame
        self.xv *= .96 # Decelerates the Player
        self.yv *= .96
        self.rect.left += self.xv # Changes the rect position
        self.rect.top += self.yv
        if self.rect.centerx < 0: self.rect.centerx = s.w+self.rect.centerx # Loop around edges of screen
        if self.rect.centery < 0: self.rect.centery = s.h+self.rect.centery
        if self.rect.centerx > s.w: self.rect.centerx = self.rect.centerx-s.w
        if self.rect.centery > s.h: self.rect.centery = self.rect.centery-s.h
        self.image = pg.transform.rotate(self.imagec, math.degrees(self.r)-180) # Rotate image
        self.rect = self.image.get_rect(center=self.rect.center)

    def reset(self): # Return to center if player dies
        self.rect.x = (s.w-30)/2
        self.rect.y = (s.h-45)/2
        self.r = math.pi
        self.xv = 0
        self.yv = 0

Если у кого-нибудь есть идеи, они будут очень благодарны. Заранее спасибо!

Редактировать: Если код для основного класса был бы полезен, я могу предоставить его, но я не думаю, что он имеет отношение к проблеме и займет много места.

Ответы [ 2 ]

1 голос
/ 23 февраля 2020

Я подозреваю, что это странное поведение связано с округлением в пределах rect [...]

Вы должны выполнять все вычисления с координатами с плавающей запятой. Добавьте атрибуты self.x соответственно self.y, которые отслеживают положение объекта. Эти атрибуты должны использоваться для вычисления текущей позиции объекта. Округлите позицию и синхронизируйте ее с местоположением атрибута .rect после вычисления новой позиции. например:

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

    def __init__(self, x = (s.w-30)/2, y = (s.h-45)/2, r = math.pi, xv = 0, yv = 0, v = .5):
        pg.sprite.DirtySprite.__init__(self)
        # [...]
        self.x = x
        self.y = y
        self.rect = pg.Rect(self.x, self.y, 30, 45)
        # [...]

   # [...]

    def move(self): # Called every frame
        self.xv *= .96 # Decelerates the Player
        self.yv *= .96

        # Changes the rect position
        self.x += self.xv
        self.y += self.yv
        self.rect.topleft = round(self.x), round(self.y)

        # bounds check
        x_changed, y_changed = False, False
        if self.rect.centerx < 0:
            self.rect.centerx = s.w+self.rect.centerx
            x_changed = True
        if self.rect.centery < 0:
            self.rect.centery = s.h+self.rect.centery
            y_changed = True
        if self.rect.centerx > s.w:
            self.rect.centerx = self.rect.centerx-s.w
            x_changed = True
        if self.rect.centery > s.h:
            self.rect.centery = self.rect.centery-s.h
            y_changed = True

        # update self.x, self.y after collision with bounds
        if x_changed:
            self.x = self.rect.x
        if y_changed:
            self.y = self.rect.y

        # [...]

    def reset(self): # Return to center if player dies
        self.x = (s.w-30)/2
        self.y = (s.h-45)/2
        self.rect.topleft = round(self.x), round(self.y)
        # [...]
0 голосов
/ 23 февраля 2020

Я не наблюдаю такого поведения, когда я изменяю ваш код для использования контроллера вида модели . Например, вместо хранения х и у в Rect. игрок должен хранить свои собственные x и y и построить Rect, используя эти x и y.

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

Я бы также рекомендовал отделить частоту кадров от скорости игры. например, вместо использования 0.5 distance / frame используйте 0.5 meters / second.

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