在Pygame中旋转和移动精灵

时间:2017-08-25 22:04:08

标签: python rotation pygame sprite

我是Python,Pygame和一般编程的新手。我正在尝试创建一个Asteroids克隆,但我无法弄清楚如何让我的播放器精灵同时移动和旋转。我使用了来自this answer的Vector2D类(尝试用键盘而不是鼠标修改它)所以我的精灵有点旋转(它不会旋转成一个完整的圆圈),但现在它不会移动。我正在尝试使用向上和向下键加速/减速并使用向左和向右箭头转动。我希望船能够面向它移动的方向。

这是迄今为止的代码:

# an asteroids clone

try:
    import sys
    import random
    import math
    import os
    import getopt
    import pygame
    from socket import *
    from pygame.locals import *
    from pygame.mixer import Sound
except ImportError, err:
    print "couldn't load module. %s" % (err)
    sys.exit(2)

# these are warnings if font or sound modules are not available.
if not pygame.font: print 'Warning, fonts disabled'
if not pygame.mixer: print 'Warning, sound disabled'


# VECTOR CLASS
class Vector2D(object):

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        return Vector2D(self.x + other.x, self.y + other.y)

    def __sub__(self, other):
        return Vector2D(self.x - other.x, self.y - other.y)

    def __mul__(self, other):
        if isinstance(other, Vector2D):
            # Vector multiplication
            return self.x * other.x + self.y * other.y
        else:
            # Scalar multiplication
            return Vector2D(self.x * other, self.y * other)

    __radd__ = __add__
    __rsub__ = __sub__
    __rmul__ = __mul__

    def get_length(self):
        return (self.x ** 2 + self.y ** 2) ** (1/2)

    def get_angle(self, other, radians=False):
        """Will return the angle between this vector and the other vector."""
        if self.get_length() == 0 or other.get_length() == 0:
            return 0
        if not radians:
            return (360 / (2 * math.pi)) * (math.atan2(other.y, other.x) - math.atan2(self.y, self.x))
        else:
            return math.atan2(other.y, other.x) - math.atan2(self.y, self.x)

    def normalize(self):
        if self.get_length() == 0:
            return Vector2D(0, 0)
        return Vector2D(self.x / self.get_length(), self.y / self.get_length())

class Player(pygame.sprite.Sprite):
    """moves ship on screen"""
    def __init__(self, image_file, pos=(0, 0)):
        super(Player, self).__init__() # call Sprite initializer
        self.original_image = pygame.image.load(image_file).convert() # RemEMBER TO CONVERT
        self.image = self.original_image # this will reference our rotated copy
        self.rect = self.image.get_rect()
        self.position = Vector2D(*pos)

        self.moving = 0 # won't move at start of game
        screen = pygame.display.get_surface()
        self.area = screen.get_rect()
        self.speed = 10
        self.state = "still"
        degree = 0
        self.reinit()

    def reinit(self):
        self.state = "still"
        self.movepos = [0,0]

    def update(self):
        newpos = self.rect.move(self.movepos)
        if self.area.contains(newpos):
            self.rect = newpos

        # Create a vector pointing at the key position
        key_pos = self.rect.move(self.movepos)

        # Create a vector pointing from the image towards the key direction
        rel_key_pos = key_pos - self.position

        # Calculate the angle between the y_axis and the vector pointing from the
        # image towards the mouse position
        y_axis = Vector2D(0, -1)
        angle = -y_axis.get_angle(rel_key_pos) # Negating bc pygame rotates counter-clockwise

        # Create the rotated copy
        self.image = pygame.transform.rotate(self.original_image, angle).convert() # Angle is absolute value!!

        # Make sure your rect represent the actual Surface
        self.rect = self.image.get_rect()

        # Since the dimension probably changed you should move its center back to where it was.
        self.rect.center = self.position.x, self.position.y
        pygame.event.pump()


    def accelerate(self):
        self.speed += 1
        self.state = "accelerate"


    def decelerate(self):
        self.speed -= 1
        self.state = "decelerate"

    def moveleft(self):
        self.movepos[0]-=(self.speed)
        self.state="moveleft"

    def moveright(self):
        self.movepos[0]+=(self.speed)
        self.state="moveright"

class Bullet():
    pass

class Asteroid():
    pass

class Background(pygame.sprite.Sprite):
    def __init__(self, image_file, location):
        pygame.sprite.Sprite.__init__(self)  #call Sprite initializer
        self.image = pygame.image.load(image_file)
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.top = location

# main event loop
def main():
    # initialize screen
    pygame.init()
    pygame.mixer.init()
    pygame.key.set_repeat(500,30)

    screen = pygame.display.set_mode((1280, 1024))
    pygame.display.set_caption('Asteroids')
    pygame.mouse.set_visible(0)

    # make background

    background = Background('data\stars1.jpg', [0,0])

    # prepare background music
    pygame.mixer.music.load('data\patakasmusic.wav')
    pygame.mixer.music.play(-1)

    # load player sprite
    global player
    player = Player('data\ship.png', [0,0])
    # initialize player sprite
    playersprite = pygame.sprite.RenderPlain((player))

    # initialize clock
    clock = pygame.time.Clock()

    # event loop
    while 1:
        clock.tick(60)
        # event loop
        for event in pygame.event.get():
            if event.type == QUIT:
                return
            elif event.type == KEYDOWN:
                if event.key == K_UP:
                    player.accelerate()
                if event.key == K_DOWN:
                    player.decelerate()
                if event.key == K_LEFT:
                    player.moveleft()
                if event.key == K_RIGHT:
                    player.moveright()
            elif event.type == KEYUP:
                if event.key == K_UP or event.key == K_DOWN:
                    player.movepos = [0,0]




        screen.fill([255, 255, 255])
        screen.blit(background.image, background.rect)
        screen.blit(player.image, (500,500))
        playersprite.draw(screen)
        playersprite.update()

        pygame.display.update()
        playersprite.update()

        pygame.display.flip()

if __name__ == '__main__': main()

1 个答案:

答案 0 :(得分:0)

我会使用另一个向量来存储精灵的direction,并添加angle_speed属性。当用户想要转动船只时,将angle_speed设置为所需的度数值,并在update方法中将方向向量旋转角速度。要移动精灵,请将direction乘以self.speed以获得速度并将其添加到self.position,然后更新矩形。

我建议使用pygame.math.Vector2类,因为它具有更多功能并且速度非常快,因为它是用C语言实现的。

import math
import pygame as pg
from pygame.math import Vector2


class Player(pg.sprite.Sprite):

    def __init__(self, pos=(420, 420)):
        super(Player, self).__init__()
        self.image = pg.Surface((70, 50), pg.SRCALPHA)
        pg.draw.polygon(self.image, (50, 120, 180), ((0, 0), (0, 50), (70, 25)))
        self.original_image = self.image
        self.rect = self.image.get_rect(center=pos)
        self.position = Vector2(pos)
        self.direction = Vector2(1, 0)  # A unit vector pointing rightward.
        self.speed = 2
        self.angle_speed = 0
        self.angle = 0

    def update(self):
        if self.angle_speed != 0:
            # Rotate the direction vector and then the image.
            self.direction.rotate_ip(self.angle_speed)
            self.angle += self.angle_speed
            self.image = pg.transform.rotate(self.original_image, -self.angle)
            self.rect = self.image.get_rect(center=self.rect.center)
        # Update the position vector and the rect.
        self.position += self.direction * self.speed
        self.rect.center = self.position


def main():
    pg.init()
    screen = pg.display.set_mode((1280, 720))
    player = Player((420, 420))
    playersprite = pg.sprite.RenderPlain((player))

    clock = pg.time.Clock()
    done = False
    while not done:
        clock.tick(60)
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True
            elif event.type == pg.KEYDOWN:
                if event.key == pg.K_UP:
                    player.speed += 1
                elif event.key == pg.K_DOWN:
                    player.speed -= 1
                elif event.key == pg.K_LEFT:
                    player.angle_speed = -4
                elif event.key == pg.K_RIGHT:
                    player.angle_speed = 4
            elif event.type == pg.KEYUP:
                if event.key == pg.K_LEFT:
                    player.angle_speed = 0
                elif event.key == pg.K_RIGHT:
                    player.angle_speed = 0

        playersprite.update()

        screen.fill((30, 30, 30))
        playersprite.draw(screen)
        pg.display.flip()

if __name__ == '__main__':
    main()
    pg.quit()