Move Character with Vector

I am teaching myself pygame and am looking at making my character able to rotate and then move in the direction they are facing.

I can do the rotation but cannot get the character to move in the direction the image is then facing.

The code is on Trinket HERE

class Bob(pygame.sprite.Sprite):
  def __init__(self, color , height , width):
    super().__init__()
    self.image = pygame.Surface([width , height])
    self.image.fill(BLACK)
    self.image.set_colorkey(BLACK)
    
    #Loading the image for the character
    self.img = pygame.image.load("char.jfif")
    #creating a copy of the image
    self.img_orig = self.img.copy()
    #defining the starting angle of the character image
    self.angle = 0
    
    self.velocity = 5
    self.rect = self.img_orig.get_rect()
    
  def moveLeft(self):
    self.angle += 1
    self.img = pygame.transform.rotate(self.img_orig, self.angle)
      
  def moveRight(self):
    self.rect.x += self.velocity
    if self.rect.x > 485:
      self.rect.x = 485
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
            
    keys = pygame.key.get_pressed()
    if keys[pygame.K_UP]:
      pSprite.moveForward()
    if keys[pygame.K_DOWN]:
      pSprite.moveDown()
    if keys[pygame.K_LEFT]:
      pSprite.moveLeft()
    if keys[pygame.K_RIGHT]:
      pSprite.moveRight()

    #---- Game Logic Here
    
      
    #--- Drawing Code Here
    #Reset the screen to blank
    screen.fill(BLUE)
    #Draw Play Area
    
    #Draw Sprites
    screen.blit(pSprite.img,(pSprite.rect.x, pSprite.rect.y))

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

You can use pygame’s Vector2 class instead of calculating the position of your sprite yourself.

I also suggest to let the sprite itself handle its movement instead of doing so in the main loop and using a clock for constant framerates and easy control of the speed of your sprites.

You also probably want to use an image format with alpha channel (like PNG).

Here’s a simple example:

import pygame

class Actor(pygame.sprite.Sprite):
    def __init__(self, pos, *grps):
        super().__init__(*grps)
        self.image = pygame.image.load('char.png').convert_alpha()
        self.image_org = self.image.copy()
        self.rect = self.image.get_rect(center=pos)
        self.pos = pygame.Vector2(pos)
        self.direction = pygame.Vector2((0, -1))
        
    def update(self, events, dt):
        pressed = pygame.key.get_pressed()
        
        # if a is pressed, rotate left with 360 degress per second
        if pressed[pygame.K_a]: self.direction.rotate_ip(dt * -360) 
        # if d is pressed, rotate right with 360 degress per second
        if pressed[pygame.K_d]: self.direction.rotate_ip(dt *  360)

        # check if should move forward or backward
        movement = 0
        if pressed[pygame.K_w]: movement =  1
        if pressed[pygame.K_s]: movement = -1
        movement_v = self.direction * movement
        if movement_v.length() > 0:
            movement_v.normalize_ip()
            # move 100px per second in the direction we're facing
            self.pos += movement_v * dt * 100
        
        # rotate the image
        self.image = pygame.transform.rotate(self.image_org, self.direction.angle_to((0, -1)))
        self.rect = self.image.get_rect(center=self.pos)
        

def main():
    pygame.init()
    screen = pygame.display.set_mode((600, 480))
    sprites = pygame.sprite.Group()
    Actor((100, 100), sprites)
    clock, dt = pygame.time.Clock(), 0
    while True:
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                return
        screen.fill('grey')
        sprites.draw(screen)
        sprites.update(events, dt)
        pygame.display.flip()
        dt = clock.tick(60) / 1000
main()

Move Character with Vector

char.png

Move Character with Vector

Method 2

Rotate the player around its center (see How do I rotate an image around its center using PyGame?):

self.angle += 1
self.img = pygame.transform.rotate(self.img_orig, self.angle)
self.rect = self.img.get_rect(center = self.rect.center)

Use an attribute x and y to store the position of the player with floating point accuracy.

class Bob(pygame.sprite.Sprite):
  def __init__(self, color , height , width):
    # [...]

    self.x, self.y = self.rect.center

Compute the direction of the player dependent on the angle with the trgonometric function math.sin and math.cos. Change the position attributes and update the rect attribute:

self.x += self.velocity * math.cos(math.radians(self.angle + 90))
self.y -= self.velocity * math.sin(math.radians(self.angle + 90))
self.rect.center = round(self.x), round(self.y)

The y-axis needs to be reversed (-dy) as the y-axis is generally pointing up, but in the PyGame coordinate system the y-axis is pointing down. In addition, a correction angle must be deducted (+ 90). Since the “angle” is 0 ° when the sprite is looking up, you need to add 90 ° to the angle for the calculation of the direction vector.

See also te in pygame while moving with the keys](How to turn the sprite in pygame while moving with the keys.


Move Character with Vector

Class Bob:

import pygame
import math
BLACK = (0,0,0)

class Bob(pygame.sprite.Sprite):
  def __init__(self, color , height , width):
    super().__init__()
    self.image = pygame.Surface([width , height])
    self.image.fill(BLACK)
    self.image.set_colorkey(BLACK)
    
    #Loading the image for the character
    self.img = pygame.image.load("char.jfif")
    #creating a copy of the image
    self.img_orig = self.img.copy()
    #defining the starting angle of the character image
    self.angle = 0
    
    self.velocity = 5
    self.rect = self.img_orig.get_rect()
    self.x, self.y = self.rect.center
    
  def rotate(self, change_angle):
    self.angle += change_angle
    self.img = pygame.transform.rotate(self.img_orig, self.angle)
    self.rect = self.img.get_rect(center = self.rect.center)
    
  def move(self, distance):
    self.x += distance * math.cos(math.radians(self.angle + 90))
    self.y -= distance * math.sin(math.radians(self.angle + 90))
    self.rect.center = round(self.x), round(self.y)
    
  def moveLeft(self):
    self.rotate(1) 
  def moveRight(self):
    self.rotate(-1)
    
  def moveForward(self):
    self.move(self.velocity)
  def moveDown(self):
    self.move(-self.velocity)

When setting the starting position of the player, you need to set the x, y and rect attribute:

pSprite = Bob(WHITE , 25,25)
pSprite.rect.x = 50
pSprite.rect.y = 50
pSprite.x, pSprite.y = pSprite.rect.center


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x