2017-10-11 14 views
2

Je rencontre des problèmes avec les sprites en mouvement. Je peux les déplacer dans les axes x et y sans problème. Ce que je ne peux pas comprendre, c'est comment puis-je les déplacer selon un certain angle. Ce que je veux dire, c'est que j'essaie de créer une fonction qui inclut l'objet que j'essaie de déplacer, sa vitesse et sa direction (qui devrait être mesurée en degrés). Quelque chose comme:Comment faire pour déplacer un sprite selon un angle dans Pygame

MovingObject(obj,speed,direction) #this is the function I'm trying to define 

Il est plus comme une « fonction de reproduction » plutôt que le mouvement ... Prenons, par exemple, que je voudrais créer un objet de la « Bullet » de classe et il veut suivre certaine direction (différent de l'axe x et y, bien sûr) En fait, je n'ai aucune idée claire de la façon de faire une telle chose et je voudrais un conseil pour y parvenir. Merci d'avoir lu ceci!

EDIT: @Joran Beasley J'ai essayé de faire ce que vous me dit ... mais je crois que je l'ai fait mal ...

import pygame, math, time 
screen=pygame.display.set_mode((320,240)) 
clock=pygame.time.Clock() 
pygame.init() 
def calculate_new_xy(old_xy,speed,angle_in_radians): 
    new_x = old_xy.x + (speed*math.cos(angle_in_radians)) 
    new_y = old_xy.y + (speed*math.sin(angle_in_radians)) 
    return new_x, new_y 
class Bullet(pygame.sprite.Sprite): 
    def __init__(self,x,y,direction,speed):   
      pygame.sprite.Sprite.__init__(self) 
      self.image=pygame.Surface((16, 16)) 
      self.image.fill((255,0,0)) 
      self.rect=self.image.get_rect() 
      self.rect.center=(x,y) 
      self.direction=math.radians(direction) 
      self.speed=speed 
    def update(self): 
      self.rect.center=calculate_new_xy(self.rect,self.speed,self.direction) 
spr=pygame.sprite.Group() 
bullet=Bullet(160,120,45,1); spr.add(bullet) 
play=True 
while play: 
    clock.tick(60) 
    for ev in pygame.event.get(): 
     if ev.type == pygame.QUIT: 
      play=False 
    screen.fill((0,0,0)) 
    spr.update() 
    spr.draw(screen) 
    pygame.display.flip() 
pygame.quit() 

L'objet se déplace, mais ... pas dans la direction indiquée ...

+0

changement à 'calculate_new_xy (self.rect.center ,. ..) 'et puis accéder x comme [0] et y que [1] et réglez votre vitesse à 2 ... cela devrait fonctionner –

Répondre

0

Je recommande d'utiliser des vecteurs. Pour obtenir la vitesse, tournez le vecteur de direction de départ Vector2(1, 0) selon l'angle et multipliez-le par la vitesse désirée. Il suffit ensuite d'ajouter ce vecteur de vitesse au vecteur de position dans la méthode update et de mettre également à jour la position rect pour déplacer l'image-objet. (Appuyez sur 'a' ou 'd' en rotation, la souris 1 ou de l'espace pour tirer.)

import pygame as pg 
from pygame.math import Vector2 


pg.init() 
screen = pg.display.set_mode((640, 480)) 
screen_rect = screen.get_rect() 

FONT = pg.font.Font(None, 24) 
BULLET_IMAGE = pg.Surface((20, 11), pg.SRCALPHA) 
pg.draw.polygon(BULLET_IMAGE, pg.Color('aquamarine1'), 
       [(0, 0), (20, 5), (0, 11)]) 


class Bullet(pg.sprite.Sprite): 

    def __init__(self, pos, angle): 
     super().__init__() 
     self.image = pg.transform.rotate(BULLET_IMAGE, -angle) 
     self.rect = self.image.get_rect(center=pos) 
     # To apply an offset to the start position, 
     # create another vector and rotate it as well. 
     offset = Vector2(40, 0).rotate(angle) 
     # Then add the offset vector to the position vector. 
     self.pos = Vector2(pos) + offset # Center of the sprite. 
     # Rotate the direction vector (1, 0) by the angle. 
     # Multiply by desired speed. 
     self.velocity = Vector2(1, 0).rotate(angle) * 9 

    def update(self): 
     self.pos += self.velocity # Add velocity to pos to move the sprite. 
     self.rect.center = self.pos # Update rect coords. 

     if not screen_rect.contains(self.rect): 
      self.kill() 


def main(): 
    clock = pg.time.Clock() 
    cannon_img = pg.Surface((40, 20), pg.SRCALPHA) 
    cannon_img.fill(pg.Color('aquamarine3')) 
    cannon = cannon_img.get_rect(center=(320, 240)) 
    angle = 0 
    bullet_group = pg.sprite.Group() # Add bullets to this group. 

    while True: 
     for event in pg.event.get(): 
      if event.type == pg.QUIT: 
       return 
      elif event.type == pg.MOUSEBUTTONDOWN: 
       # Left button fires a bullet from center with 
       # current angle. Add the bullet to the bullet_group. 
       if event.button == 1: 
        bullet_group.add(Bullet(cannon.center, angle)) 

     keys = pg.key.get_pressed() 
     if keys[pg.K_a]: 
      angle -= 3 
     elif keys[pg.K_d]: 
      angle += 3 
     if keys[pg.K_SPACE]: 
      bullet_group.add(Bullet(cannon.center, angle)) 

     # Rotate the cannon image. 
     rotated_cannon_img = pg.transform.rotate(cannon_img, -angle) 
     cannon = rotated_cannon_img.get_rect(center=cannon.center) 

     bullet_group.update() 

     # Draw 
     screen.fill((30, 40, 50)) 
     screen.blit(rotated_cannon_img, cannon) 
     bullet_group.draw(screen) 
     txt = FONT.render('angle {:.1f}'.format(angle), True, (150, 150, 170)) 
     screen.blit(txt, (10, 10)) 
     pg.display.update() 

     clock.tick(30) 

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

En ce qui concerne le code dans votre exemple supplémentaire, la solution la plus simple est de calculer la speed_x et speed_y (» vélocité "serait plus approprié) dans la méthode __init__, puis il suffit de mettre à jour les attributs self.rect.x et y dans la méthode update.

import math 
import pygame 


pygame.init() 

screen = pygame.display.set_mode((640, 480)) 
clock = pygame.time.Clock() 

BULLET_IMAGE = pygame.Surface((20, 11), pygame.SRCALPHA) 
pygame.draw.polygon(BULLET_IMAGE, pygame.Color('aquamarine1'), 
       [(0, 0), (20, 5), (0, 11)]) 


class Bullet(pygame.sprite.Sprite): 

    def __init__(self, x, y, angle, speed): 
     pygame.sprite.Sprite.__init__(self) 
     # Rotate the bullet image (negative angle because y-axis is flipped). 
     self.image = pygame.transform.rotate(BULLET_IMAGE, -angle) 
     self.rect = self.image.get_rect(center=(x, y)) 
     angle = math.radians(angle) 
     self.speed_x = speed * math.cos(angle) 
     self.speed_y = speed * math.sin(angle) 

    def update(self): 
     self.rect.x += self.speed_x 
     self.rect.y += self.speed_y 

spr = pygame.sprite.Group() 
bullet = Bullet(10, 10, 60, 3) 
bullet2 = Bullet(10, 10, 30, 3) 
spr.add(bullet, bullet2) 

play = True 
while play: 
    clock.tick(60) 
    for ev in pygame.event.get(): 
     if ev.type == pygame.QUIT: 
      play = False 
    screen.fill((30,30,40)) 
    spr.update() 
    spr.draw(screen) 
    pygame.display.flip() 

pygame.quit() 

Il y a un problème, parce que pygame.Rect s ne peuvent avoir ints que les attributs x et y, de sorte que le mouvement ne sera pas correct à 100%. Pour résoudre ce problème, vous devez stocker le coords/position de l'image-objet variables distinctes, ajouter la vitesse à les mettre à jour et après le rect:

# In `__init__`. 
    self.pos_x = x 
    self.pos_y = y 

def update(self): 
    self.pos_x += self.speed_x 
    self.pos_y += self.speed_y 
    self.rect.center = (self.pos_x, self.pos_y) 
+0

J'apprécie vraiment votre réponse ... Mais j'ai peur de dire que ... c'est un peu déroutant ... Aussi ... Je ne sais pas si c'est ce que je voulais obtenir ... Probablement je devrais J'ai dit quelque chose comme: je voudrais définir une fonction qui crée un "objet en mouvement" qui bouge dans une certaine direction ... Peut-être ... si tu m'expliques ... en plus simple ... des mots ... ? (Je suis désolé, c'est un peu dur pour moi de comprendre ... – DarkBlood202

+0

Savez-vous comment fonctionnent les vecteurs? – skrx

+0

Je suppose ... Je ne sais pas – DarkBlood202

2

vous avez juste besoin d'un peu TRIG base

def calculat_new_xy(old_xy,speed,angle_in_radians): 
    new_x = old_xy.X + (speed*math.cos(angle_in_radians)) 
    new_y = old_xy.Y + (speed*math.sin(angle_in_radians)) 
    return new_x, new_y 

--- --- modifier

Voici votre code ci-dessus édité au travail

import pygame, math, time 
screen=pygame.display.set_mode((320,240)) 
clock=pygame.time.Clock() 
pygame.init() 
def calculate_new_xy(old_xy,speed,angle_in_radians): 
    new_x = old_xy[0] + (speed*math.cos(angle_in_radians)) 
    new_y = old_xy[1] + (speed*math.sin(angle_in_radians)) 
    return new_x, new_y 
class Bullet(pygame.sprite.Sprite): 
    def __init__(self,x,y,direction,speed): 
      pygame.sprite.Sprite.__init__(self) 
      self.image=pygame.Surface((16, 16)) 
      self.image.fill((255,0,0)) 
      self.rect=self.image.get_rect() 
      self.rect.center=(x,y) 
      self.direction=math.radians(direction) 
      self.speed=speed 
    def update(self): 
      self.rect.center=calculate_new_xy(self.rect.center,self.speed,self.direction) 
spr=pygame.sprite.Group() 
bullet=Bullet(160,120,45,2); spr.add(bullet) 
play=True 
while play: 
    clock.tick(60) 
    for ev in pygame.event.get(): 
     if ev.type == pygame.QUIT: 
      play=False 
    screen.fill((0,0,0)) 
    spr.update() 
    spr.draw(screen) 
    pygame.display.flip() 
pygame.quit() 
+0

Et ... Cela n'a pas fonctionné. Merci quand même ... Probablement j'ai juste mal compris la façon dont je suis censé l'utiliser ... – DarkBlood202

+0

Oh ça marche aussi bien! Merci de votre aide! – DarkBlood202