Answer the question
In order to leave comments, you need to log in
Pygame - Python math problem
Here is the code, in theory it should draw small 4x4 rectangles in front of the moving car (in the end they overlap each other and look like a line). In this case, the sprite of the car can be directed at any angle. And the problem is that this line of rectangles does not in all cases go at the same angle as the machine. When entering integer angles (0, 90, 180...), the line is displayed correctly (see figure, 3rd picture). And at angles such as 222 degrees or 333, the angle of inclination of the line and the trajectory of the machine do not match. I think that the problem is in calculating the coordinates of the rectangles, but I don’t understand where the error is.
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from __future__ import division # / - деление
import pygame, math
from pygame import *
WIN_WIDTH = 800 #Ширина создаваемого окна
WIN_HEIGHT = 600 # Высота
SKREEN_COLOR = (100,255,200)
WIDTH = 3000 #Ширина поля робота
HEIGHT = 3000 #Высота
PATH_ROBOT_IMAGE = 'image/robot.png'
######## ПЛАТФОРМЫ ###########
PLATFORM_WIDTH = 4
PLATFORM_HEIGHT = 4
PLATFORM_COLOR = "#FF6262"
##############################
backward = forward = False #Робот стоит
############## Класс для отрисовки робота
class Sprite(pygame.sprite.Sprite): #Наследование класса Sprite
def __init__(self, filename, startx, starty):
pygame.sprite.Sprite.__init__(self)#инициализация __init__ в классе Sprite
self.image = pygame.image.load(filename)
self.rect = self.image.get_rect()
self.rect.x = startx
self.rect.y = starty
def render(self, screen, pos = (0, 0), angle = 0):
#Поворачиваю картинку
image = pygame.transform.rotate(self.image, angle)
self.rect = image.get_rect(center=self.rect.center)
screen.blit(image, self.rect)
def move(self, forward, backward, angle, path):
rad_alfa = angle * (math.pi/180)
if forward:
self.rect.x = self.rect.x + path*math.cos(rad_alfa)
self.rect.y = self.rect.y - path*math.sin(rad_alfa)
if backward:
self.rect.y +=path*math.sin(rad_alfa)
self.rect.x -=path*math.cos(rad_alfa)
def get_position(self):
return self.rect.center
#image = 0
############## Класс для отрисовки платформ
class Platform(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)#инициализация __init__ в классе Sprite
self.image = Surface((PLATFORM_WIDTH, PLATFORM_HEIGHT))
self.image.fill(Color(PLATFORM_COLOR))
self.rect = Rect(x, y, PLATFORM_WIDTH, PLATFORM_HEIGHT)
pygame.init()
screen = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT)) #Размер экрана
robot = Sprite(PATH_ROBOT_IMAGE, 400, 300) #Создание робота на координатах 0,0
entities = pygame.sprite.Group() # Все объекты
platforms = [] # то, во что мы будем врезаться или опираться
#entities.add(robot)#Добавляем спрайт робота в группу ко всем объектам
def position(x0 ,y0, alfap, distanse):
rad_alfap = alfap * (math.pi/180)
y = float(y0) + (math.sin(rad_alfap)*distanse)
x = float(x0) + (math.cos(rad_alfap)*distanse)
pos=(x, y) #Отображаем ось Oy вертикально вверх
print pos
return pos
clok = pygame.time.Clock()
while True:
for e in pygame.event.get():
if e.type == pygame.QUIT: exit(0)
if e.type == pygame.KEYDOWN and e.key == pygame.K_ESCAPE: exit(0)
screen.fill((100, 255, 100))
forward = True #Движение вперед
angle =222 #Угол движения (222 90 333)
path =2 #Cкорость движения
robot.move(forward, backward, angle, path) #Движение робота
distanse = 70 # Расстояния на котором отмечается прямоугольник перед роботом
pos_robot = robot.get_position() #Получения координат спрайта робота (размер 25х16)
ppos = position(pos_robot[0], -(pos_robot[1]), angle, distanse) #Нахождении координат прямоугольника
robot.render(screen, (400, 400), angle) #Поворот спрайта на угол angle
pf = Platform(ppos[0], -ppos[1])
entities.add(pf)
platforms.append(pf)
entities.draw(screen)
pygame.display.update()
clok.tick(30)
Answer the question
In order to leave comments, you need to log in
Something is wrong with the very formula for calculating the movement of the machine. If you set the angle to 45 and the speed, for example, 10, then the trajectory will already become much closer to the truth. And with a speed of 1, the car will move strictly vertically, regardless of the angle.
Although here is an option. Store the coordinate separately.
The current needs to be finalized by get_position. Let it return the saved coordinates better.
class Sprite(pygame.sprite.Sprite): #Наследование класса Sprite
def __init__(self, filename, startx, starty):
pygame.sprite.Sprite.__init__(self)#инициализация __init__ в классе Sprite
self.image = pygame.image.load(filename)
self.rect = self.image.get_rect()
self.rect.x = startx
self.rect.y = starty
self.x = float(startx)
self.y = float(startx)
def render(self, screen, pos = (0, 0), angle = 0):
#Поворачиваю картинку
image = pygame.transform.rotate(self.image, angle)
self.rect = image.get_rect(center=self.rect.center)
screen.blit(image, self.rect)
def move(self, forward, backward, angle, path):
rad_alfa = angle * (math.pi/180)
if forward:
self.x = self.x + (path * math.cos(rad_alfa))
self.y = self.y - (path * math.sin(rad_alfa))
self.rect.x = self.x
self.rect.y = self.y
if backward:
self.y +=path*math.sin(rad_alfa)
self.x -=path*math.cos(rad_alfa)
self.rect.x = self.x
self.rect.y = self.y
def get_position(self):
return self.rect.center
There was another small problem, as you can see from the def render() function, the rotated car is drawn to the screen via screen.blit(image, self.rect) . I need the camera to fix relative to the car and move with it, I put all the platforms in one entity array, and when the camera moves, they are drawn relative to it. Using camera.update(robot), the camera is fixed relative to the center of the screen, and all elements are displayed incorrectly ...
Probably the car should be added to the same array as the platforms, but with a rotated image, I can't do it
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from __future__ import division # / - деление
import pygame, math
from pygame import *
WIN_WIDTH = 800 #Ширина создаваемого окна
WIN_HEIGHT = 600 # Высота
SKREEN_COLOR = (100,255,200)
WIDTH = 3000 #Ширина поля
HEIGHT = 3000 #Высота
PATH_ROBOT_IMAGE = 'image/robot.png'
######## ПЛАТФОРМЫ ###########
PLATFORM_WIDTH = 4
PLATFORM_HEIGHT = 4
PLATFORM_COLOR = "#FF6262"
##############################
path = 5
entities = pygame.sprite.Group() # Все объекты
platforms = [] # то, во что мы будем врезаться или опираться
angle = 360 #Начальный уго
backward = forward = False #Робот стоит
############## Класс для отрисовки робота]
class Camera(object):
def __init__(self, camera_func, width, height):
self.camera_func = camera_func
self.state = Rect(0, 0, width, height)
def apply(self, target):
return target.rect.move(self.state.topleft)
def update(self, target):
self.state = self.camera_func(self.state, target.rect)
def camera_configure(camera, target_rect):
l, t, _, _ = target_rect
_, _, w, h = camera
l, t = -l+WIN_WIDTH / 2, -t+WIN_HEIGHT / 2
l = min(5000, l) # Не движемся дальше левой границы
l = max(-(camera.width-WIN_WIDTH), l) # Не движемся дальше правой границы
t = max(-(camera.height-WIN_HEIGHT), t) # Не движемся дальше нижней границы
t = min(5000, t) # Не движемся дальше верхней границы
return Rect(l, t, w, h)
camera = Camera(camera_configure, WIDTH, HEIGHT)
class Sprite(pygame.sprite.Sprite): #Наследование класса Sprite
def __init__(self, filename, startx, starty):
pygame.sprite.Sprite.__init__(self)#инициализация __init__ в классе Sprite
self.image = pygame.image.load(filename)
self.rect = self.image.get_rect()
self.rect.x = startx
self.rect.y = starty
self.x = float(startx)
self.y = float(startx)
def render(self, screen, pos = (0, 0), angle = 0):
#Поворачиваю картинку
pygame.sprite.Sprite.__init__(self)#инициализация __init__ в классе Sprite
image = pygame.transform.rotate(self.image, angle)
self.rect = image.get_rect(center=self.rect.center)
robot_r = screen.blit(image, self.rect)
def move(self, forward, backward, angle, path):
rad_alfa = angle * (math.pi/180)
if forward:
self.x = self.x + (path * math.cos(rad_alfa))
self.y = self.y - (path * math.sin(rad_alfa))
self.rect.x = self.x
self.rect.y = self.y
if backward:
self.y +=path*math.sin(rad_alfa)
self.x -=path*math.cos(rad_alfa)
self.rect.x = self.x
self.rect.y = self.y
def get_position(self):
return self.rect.center
############## Класс для отрисовки платформ
class Platform(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)#инициализация __init__ в классе Sprite
self.image = Surface((PLATFORM_WIDTH, PLATFORM_HEIGHT))
self.image.fill(Color(PLATFORM_COLOR))
self.rect = Rect(x, y, PLATFORM_WIDTH, PLATFORM_HEIGHT)
pygame.init()
screen = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT)) #Размер экрана
robot = Sprite(PATH_ROBOT_IMAGE, 0, 0) #Создание робота на координатах 0,0
list_sonic = {1: 0, 2: 45, 3: 90, 4: 180, 5: 270, 6: 315}
def real_alige(teta, namber_sonic): #Угол вектора
if 0<=teta<=90 :
alfat = teta + list_sonic[namber_sonic]
print '1111'
elif 90<teta<=180:
if namber_sonic>=5: alfat=list_sonic[namber_sonic]-(360-teta)
else: alfat = teta + list_sonic[namber_sonic]
elif 180<teta<=270:
if namber_sonic>=4: alfat=list_sonic[namber_sonic]-(360-teta)
else: alfat = teta + list_sonic[namber_sonic]
elif 270<teta<=360:
if namber_sonic>=3: alfat=list_sonic[namber_sonic]-(360-teta)
else: alfat = teta + list_sonic[namber_sonic]
#print alfat
return alfat
def position(x0 ,y0, alfap, distanse):
rad_alfap = alfap * (math.pi/180)
y = float(y0) + (math.sin(rad_alfap)*distanse) + math.sin(rad_alfap)*12.5
x = float(x0) + (math.cos(rad_alfap)*distanse) + math.cos(rad_alfap)*12.5
pos=(x, y)
return pos
clok = pygame.time.Clock()
while True:
for e in pygame.event.get():
if e.type == pygame.QUIT: exit(0)
if e.type == pygame.KEYDOWN and e.key == pygame.K_ESCAPE: exit(0)
if e.type == pygame.KEYDOWN and e.key == pygame.K_LEFT:
angle += 5
if angle >=360: angle = 0
if e.type == pygame.KEYDOWN and e.key == pygame.K_RIGHT:
angle -= 5
if angle <=0: angle = 360
if e.type == pygame.KEYDOWN and e.key == pygame.K_DOWN: backward = True
if e.type == pygame.KEYDOWN and e.key == pygame.K_UP: forward = True
if e.type == pygame.KEYUP and e.key == pygame.K_DOWN: backward = False
if e.type == pygame.KEYUP and e.key == pygame.K_UP: forward = False
screen.fill((100, 255, 210))
path =4
robot.move(forward, backward, angle, path) #Движение
pos_robot = robot.get_position()
ppos = position(pos_robot[0], -(pos_robot[1]), real_alige(angle, 1), 70)
pf = Platform(ppos[0], -ppos[1])
entities.add(pf)
platforms.append(pf)
robot.render(screen, (ppos[0], ppos[1]), angle) #Поворот
for e in entities:
screen.blit(e.image, camera.apply(e))
camera.update(robot)
pygame.display.update()
clok.tick(30)
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question