2017-08-25 5 views
1

Ich bin neu in Python, Pygame und Programmierung im Allgemeinen. Ich versuche einen Asteroids-Klon zu erstellen, aber ich kann nicht herausfinden, wie ich mein Player-Sprite gleichzeitig bewegen und drehen lassen kann. Ich habe die Vector2D-Klasse von this answer (versucht, es für die Tastatur anstelle der Maus zu ändern), so dass mein Sprite sich dreht (es wird nicht in einem vollständigen Kreis drehen), aber jetzt wird es nicht bewegen. Ich versuche mit den Auf- und Ab-Tasten zu beschleunigen/zu verzögern und mit den Links- und Rechtspfeilen zu drehen. Ich möchte, dass das Schiff in die Richtung sieht, in die es sich bewegt.Ein Sprite in Pygame rotieren und verschieben

Hier ist der Code so weit:

# 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() 
+0

Bitte nehmen Sie sich einen Blick auf die [MCVE Seite] (https implementiert ist: // Stackoverflow .com/hilfe/mcve). – skrx

Antwort

0

ich einen anderen Vektor, der die direction des Sprites zu speichern verwenden würde und auch ein angle_speed Attribut hinzufügen. Wenn der Benutzer das Schiff drehen möchte, stellen Sie angle_speed auf den gewünschten Wert in Grad ein und drehen Sie den Richtungsvektor in der Methode update um die Winkelgeschwindigkeit. Um das Sprite zu bewegen, multiplizieren Sie die direction mit self.speed, um die Geschwindigkeit zu erhalten, und fügen Sie sie zum self.position hinzu, dann aktualisieren Sie das Rect.

Ich empfehle die pygame.math.Vector2 Klasse zu verwenden, da es verfügt über mehr Features und ist auch schnell ziemlich, weil es in 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() 
+0

Definitiv eine gute Idee, die Vektorklasse von pygame zu verwenden, aber warum nicht einfach den Winkel speichern, anstatt ihn aus dem Richtungsvektor in jedem Update zu berechnen? –

+0

@WyattIsrael ja, das ist einfacher. Ich brauchte nur die Winkelberechnung in der ursprünglichen Version dieses Beispiels, weil ich in Richtung der Maus drehen musste. Ich habe nur vergessen, diese Zeile zu ändern. – skrx

+0

@skrx Ich bekomme eine Fehlermeldung, dass es kein pygame.math-Modul gibt. Wo kann ich es finden? Ich benutze Windows BTW. – rebawan

Verwandte Themen