JT Johnson
JT Johnson

Reputation: 91

Pygame - making a sprite move in the direction it is facing

I'm making a top down car racing game and I want to make the car rotate when you press the left and right keys (I’ve already done that part), the sprite's rotation is stored in a variable as degrees. I'd like to be able to make it move according to acceleration in the direction it is facing. I can figure out the acceleration part myself, it's just figuring out what pixel exactly is in that direction. Can anyone give me some simple code to help with this?

Here are the contents of the class that are relevant:

def __init__(self, groups):
    super(Car, self).__init__(groups)
    self.originalImage = pygame.image.load(os.path.join("Data", "Images", "Car.png")) #TODO Make dynamic
    self.originalImage.set_colorkey((0,255,0))
    self.image = self.originalImage.copy() # The variable that is changed whenever the car is rotated.

    self.originalRect = self.originalImage.get_rect() # This rect is ONLY for width and height, the x and y NEVER change from 0!
    self.rect = self.originalRect.copy() # This is the rect used to represent the actual rect of the image, it is used for the x and y of the image that is blitted.

    self.velocity = 0 # Current velocity in pixels per second
    self.acceleration = 1 # Pixels per second (Also applies as so called deceleration AKA friction)
    self.topSpeed = 30 # Max speed in pixels per second
    self.rotation = 0 # In degrees
    self.turnRate = 5 # In degrees per second

    self.moving = 0 # If 1: moving forward, if 0: stopping, if -1: moving backward


    self.centerRect = None

def update(self, lastFrame):
    if self.rotation >= 360: self.rotation = 0
    elif self.rotation < 0: self.rotation += 360

    if self.rotation > 0:
        self.image = pygame.transform.rotate(self.originalImage.copy(), self.rotation)
        self.rect.size = self.image.get_rect().size
        self.center() # Attempt to center on the last used rect

    if self.moving == 1:
        self.velocity += self.acceleration #TODO make time based

    if self.velocity > self.topSpeed: self.velocity = self.topSpeed # Cap the velocity

Upvotes: 5

Views: 13337

Answers (2)

Eli Bendersky
Eli Bendersky

Reputation: 273416

I can't really do better than pointing you to this tutorial (*). In particular, the first part explains how to do rotation and make the sprites move in certain directions.


(*) Shameless plug :-) but very relevant to the question.

Upvotes: 1

ninMonkey
ninMonkey

Reputation: 7501

Trigonometry: The formula to get your coordinate is:

# cos and sin require radians
x = cos(radians) * offset
y = sin(radians) * offset

You use velocity for offset. (This means a negative velocity will drive backwards).

so:

def rad_to_offset(radians, offset): # insert better func name.
    x = cos(radians) * offset
    y = sin(radians) * offset
    return [x, y]

loop_update is something like:

# vel += accel
# pos += rad_to_offset( self.rotation, vel )

math.cos, math.sin: uses radians, so

storing rotations as radians is simpler. If you want to define speed / etc as degrees, you still can.

# store radians, but define as degrees
car.rotation_accel = radians(45)
car.rotation_max_accel = radians(90)

Upvotes: 6

Related Questions