# How do I move a character based on it's rotation?

## Issue

I have a character in PyGame which I want to move forward depending on its rotation. Currently it’s very strange and wonky.

Here’s all my code: https://www.toptal.com/developers/hastebin/enapuravet.lua

Here’s the relevent code:

def rotate(self, amount):
self.rotation += amount
if self.rotation == 181:
self.rotation = -180
elif self.rotation == -181:
self.rotation = 180
print(self.rotation)
self.capybara = pygame.transform.rotate(self.base_capybara, self.rotation)
self.rect = self.capybara.get_rect(center = self.rect.center)

def move_forward(self, speed):
print(self.rotation)
new_coordinates = calculate_new_xy((self.x, self.y), 2, self.rotation*(math.pi/180))
self.x = new_coordinates[0]
self.y = new_coordinates[1]
self.rect = self.capybara.get_rect(center = (self.x, self.y))

return new_x, new_y

Here’s what it does:
https://gyazo.com/3b7bf1c5b2e760a53913b6d3acae6e67

I also tried some other x_y calculating functions like this:

move_vec = pygame.math.Vector2()
move_vec.from_polar((speed, angle_in_degrees))
return old_xy + move_vec

but they had the same/very similar results.

This is the capybara:

## Solution

Since pygame.Rect is supposed to represent an area on the screen, a pygame.Rect object can only store integral data.

The coordinates for Rect objects are all integers. […]

If you want to store object positions with floating point accuracy, you have to store the location of the object in separate variables respectively attributes and to synchronize the pygame.Rect object. round the coordinates and assign it to the location (e.g. .center) of the rectangle.

The unit of the angle of math.sin and math.cos is Randian. You needs to convert the angle from degrees to radians with math.radians:

class Capybara:
def __init__(self, size_multiplier):
# [...]

self.x, self.y = 300, 300
self.rect = self.capybara.get_rect(center = (round(self.x), round(self.y)))

def rotate(self, amount):
self.rotation += amount
ifv self.rotation > 360:
self.rotation -= 360
elif self.rotation < 0:
self.rotation += 360
self.capybara = pygame.transform.rotate(self.base_capybara, self.rotation)
self.rect = self.capybara.get_rect(center = (round(self.x), round(self.y)))

def move(self, move):
self.x += move * math.cos(math.radians(self.rotation + 90))
self.y -= move * math.sin(math.radians(self.rotation + 90))

Minimal example:

import pygame, math
pygame.init()

size = width, height = 600, 600
green = 50, 168, 82

screen = pygame.display.set_mode(size)

class Capybara:
def __init__(self, size_multiplier):
self.o_size = 92, 206
self.new_size = (self.o_size[0] * size_multiplier,self.o_size[1] * size_multiplier)
self.capybara = pygame.transform.scale(self.capybara, self.new_size)
self.base_capybara = self.capybara
self.rotation = 0
self.x, self.y = 300, 300
self.rect = self.capybara.get_rect(center = (round(self.x), round(self.y)))

def rotate(self, amount):
self.rotation += amount
if self.rotation > 360:
self.rotation -= 360
elif self.rotation < 0:
self.rotation += 360
self.capybara = pygame.transform.rotate(self.base_capybara, self.rotation)
self.rect = self.capybara.get_rect(center = (round(self.x), round(self.y)))

def move(self, move):
self.x += move * math.cos(math.radians(self.rotation + 90))
self.y -= move * math.sin(math.radians(self.rotation + 90))

capybara = Capybara(0.8)

fpsClock = pygame.time.Clock()

rotate_l = False
rotate_r = False

while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()

quit()

keys = pygame.key.get_pressed()
rotate = keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]
move = keys[pygame.K_DOWN] - keys[pygame.K_UP]
capybara.move(-move * 5)
capybara.rotate(-rotate)

screen.fill(green)
screen.blit(capybara.capybara, capybara.rect)
pygame.display.update()
fpsClock.tick(60)