Oct-11-2019, 07:07 PM
Hello everyone! I'm a new pygame/python (wannabe) programmer, and I stepped into a problem.
I want to have a character displayed on the screen, being able to move in every direction. When I left-click on it, he is "selectionned"(yes I'm aware of the error). When selected, if I right-click somewhere else, it will move to that position, and stop once destination reached. Until there, no problem at all, everything is working as intended.
However, I want to add the possibility of my character rotating to the direction where it is going. While the rotation is working fine, the problem is -and as I saw through my internet research, a common one- that the image is actually being displaced. The reason for it, I know it very well: the "rect" cannot be circular, so the image is moving, to look like a square on its tip. As a square diagonal is bigger than its side, the image is moving to the bottom right of the screen, the worst being when you're at a 45° angle. Here is a gif to make it clearer:
![[Image: 7GfVA.gif]](https://i.stack.imgur.com/7GfVA.gif)
While i would like something like:
![[Image: diqBY.gif]](https://i.stack.imgur.com/diqBY.gif)
Note that I don't mind the hitbox changing of size, but if possible I wouldn't be nitpicky.
I've seen many ways to correct it, however, all of them were really out of reach for me, even more as English is not my first language. I see that most people use "pygame.transform.rotate()", however my code is a heavily modified version of a game I previously made with a friend, and I have no idea how to adapt it. Here it is:
I want to have a character displayed on the screen, being able to move in every direction. When I left-click on it, he is "selectionned"(yes I'm aware of the error). When selected, if I right-click somewhere else, it will move to that position, and stop once destination reached. Until there, no problem at all, everything is working as intended.
However, I want to add the possibility of my character rotating to the direction where it is going. While the rotation is working fine, the problem is -and as I saw through my internet research, a common one- that the image is actually being displaced. The reason for it, I know it very well: the "rect" cannot be circular, so the image is moving, to look like a square on its tip. As a square diagonal is bigger than its side, the image is moving to the bottom right of the screen, the worst being when you're at a 45° angle. Here is a gif to make it clearer:
![[Image: 7GfVA.gif]](https://i.stack.imgur.com/7GfVA.gif)
While i would like something like:
![[Image: diqBY.gif]](https://i.stack.imgur.com/diqBY.gif)
Note that I don't mind the hitbox changing of size, but if possible I wouldn't be nitpicky.
I've seen many ways to correct it, however, all of them were really out of reach for me, even more as English is not my first language. I see that most people use "pygame.transform.rotate()", however my code is a heavily modified version of a game I previously made with a friend, and I have no idea how to adapt it. Here it is:
import pygame,random,math from pygame.locals import * class Hero(pygame.sprite.Sprite): def __init__(self, x, y,DIRECTION,upKeyPressed,downKeyPressed,leftKeyPressed,rightKeyPressed, leftMousePressed, rightMousePressed, oneKeyPressed, HP, game): pygame.sprite.Sprite.__init__(self) self.image = self.perso_rotated_surf = pygame.image.load("Sprites/Ant-rot.png").convert_alpha() self.step1 = pygame.image.load("Sprites/Ant-1.png").convert_alpha() self.step2 = pygame.image.load("Sprites/Ant-mid.png").convert_alpha() self.step3 = pygame.image.load("Sprites/Ant-3.png").convert_alpha() self.step4 = pygame.image.load("Sprites/Ant-mid.png").convert_alpha() self.rect = self.image.get_rect() self.step = [self.step1,self.step2,self.step3,self.step4] self.perso_angle = 0 self.ticker = 0 self.rect.x = x self.rect.y = y self.center = None self.DIRECTION = DIRECTION self.upKeyPressed = upKeyPressed self.downKeyPressed = downKeyPressed self.leftKeyPressed = leftKeyPressed self.rightKeyPressed = rightKeyPressed self.leftMousePressed = leftMousePressed self.rightMousePressed = rightMousePressed self.oneKeyPressed = oneKeyPressed self.RIGHT, self.LEFT, self.UP, self.DOWN = "right left up down".split() self.game = game self.current_frame = 0 self.vitessex = 0 self.accx = 0 self.vitessey = 0 self.accy = 0 self.coordx = 1920/2 self.coordy = 1080/2 self.centerc = None self.perso_angle = 0 self.selection = 0, 0 self.selectionned = False self.xdest = 0 self.ydest = 0 self.angledeg = 0 def centerPos(self): self.center = (self.rect.x + 56, self.rect.y + 75) self.centerc = (self.coordx, self.coordy) def update(self): xc, yc = self.center xd, yd = self.selection if self.leftMousePressed: xm, ym = self.selection if xm >= (xc - 56) and xm < (xc + 56) and ym >= (yc - 75) and ym < (yc + 75): self.selectionned = True else: self.selectionned = False if self.rightMousePressed: self.xdest = xd self.ydest = yd if (xd-xc) >= 0: if (yd-yc) == 0: self.vitessey = 0 self.vitessex = -5 if (yd-yc) > 0: angled = (math.atan((xd-xc)/(yd-yc))) self.angledeg = ((angled*180) / 3.1415) + 90 #1 if self.selectionned == True: angle2 = (self.angledeg * 3.1415) / 180 self.vitessex = -5 * math.cos(angle2) self.vitessey = 5 * math.sin(angle2) if (yd-yc) < 0: angled = (math.atan((xd-xc)/(yd-yc))) self.angledeg = ((angled*180) / 3.1415) + 270 #2 if self.selectionned == True: angle2 = (self.angledeg * 3.1415) / 180 self.vitessex = -5 * math.cos(angle2) self.vitessey = 5 * math.sin(angle2) if (xd-xc) < 0: if (yd-yc) == 0: self.vitessey = 0 self.vitessex = 5 if (yd-yc) > 0: angled = (math.atan((xd-xc)/(yd-yc))) self.angledeg = ((angled*180) / 3.1415) + 90 #3 if self.selectionned == True: angle2 = (self.angledeg * 3.1415) / 180 self.vitessex = -5 * math.cos(angle2) self.vitessey = 5 * math.sin(angle2) if (yd-yc) < 0: angled = (math.atan((xd-xc)/(yd-yc))) self.angledeg = ((angled*180) / 3.1415) + 270 #4 if self.selectionned == True: angle2 = (self.angledeg * 3.1415) / 180 self.vitessex = -5 * math.cos(angle2) self.vitessey = 5 * math.sin(angle2) if self.vitessey != 0 or self.vitessex != 0: self.perso_angle = (self.angledeg + 90) self.perso_rotated_surf = pygame.transform.rotate(self.image, self.perso_angle) self.rect = self.perso_rotated_surf.get_rect(center=self.centerc) if xc >= (self.xdest - 10) and xc <= (self.xdest + 10) and yc >= (self.ydest - 10) and yc <= (self.ydest + 10): self.vitessex = 0 self.vitessey = 0 self.ticker += 1 if self.ticker % 8 == 0: self.current_frame = (self.current_frame + 1) % 4 self.vitessex += self.accx self.coordx += self.vitessex self.rect.x = self.coordx self.accx = 0 if self.vitessey != 0 or self.vitessex != 0: self.image = self.step[self.current_frame] self.perso_rotated_surf = pygame.transform.rotate(self.image, self.perso_angle) self.vitessey += self.accy self.coordy += self.vitessey self.rect.y = self.coordy self.accy = 0 class Room(object): wall_list = None def __init__(self): self.bullet = pygame.sprite.Group() class Room1(Room): def __init__(self): Room.__init__(self) self.background = pygame.image.load("room/room1.png").convert_alpha() mobs = [] class GameMain(): done = False def __init__(self,width = 1920, height = 1080): pygame.mixer.pre_init(44100, -16, 2, 2048) pygame.init() self.arial_font = pygame.font.SysFont("arial", 30) self.width, self.height = width, height pygame.display.set_caption("Ants") self.screen = pygame.display.set_mode((self.width, self.height), pygame.FULLSCREEN) self.hero = Hero(100,200,"UP",False,False,False,False,False,False,False,20, self) self.all_sprite_list = pygame.sprite.Group() self.all_sprite_list.add(self.hero) self.rooms = [[Room1()]] self.clock = pygame.time.Clock() self.current_x = 0 self.current_y = 0 self.current_screen = "title" self.current_room = self.rooms[self.current_y][self.current_x] def main_loop(self): while not self.done: if self.current_screen == "game": self.handle_events() self.hero.centerPos() self.draw() self.all_sprite_list.update() self.change_room() self.current_room.bullet.update() elif self.current_screen == "title": self.handle_events_title() self.draw_title() self.clock.tick(60) pygame.quit() def handle_events_title(self): events = pygame.event.get() for event in events: if event.type == pygame.QUIT: self.done = True if event.type == KEYDOWN: if event.key == K_RETURN: self.current_screen = "game" if event.key == K_F4 : self.done = True def draw_title(self): self.screen.fill(Color("Black")) credit = pygame.image.load("background_menu.jpg") self.screen.blit(credit,(0,0)) pygame.display.flip() def draw(self): self.screen.fill((255,255, 255)) background = self.current_room.background self.screen.blit(background,(0,0)) self.all_sprite_list.draw(self.screen) self.screen.blit(self.hero.perso_rotated_surf, self.hero.rect) pygame.display.flip() def change_room(self): if self.hero.coordx > 1921 : self.hero.coordx = 0 self.current_room = self.rooms[self.current_y][self.current_x] elif self.hero.coordx < 0 : self.hero.coordx = 1919 self.current_room = self.rooms[self.current_y][self.current_x] elif self.hero.coordy < 0 : self.hero.coordy = 1079 self.current_room = self.rooms[self.current_y][self.current_x] elif self.hero.coordy > 1080 : self.hero.coordy = 0 self.current_room = self.rooms[self.current_y][self.current_x] def handle_events(self): events = pygame.event.get() for event in events: if event.type == pygame.QUIT: self.done = True elif event.type == KEYDOWN : if event.key == (K_LALT and K_F4): self.done = True if event.type == MOUSEBUTTONDOWN : if pygame.mouse.get_pressed() == (1, 0, 0): self.hero.leftMousePressed = True if pygame.mouse.get_pressed() == (0, 0, 1): self.hero.rightMousePressed = True elif event.type == MOUSEMOTION : self.hero.selection = event.pos elif event.type == MOUSEBUTTONUP : if pygame.mouse.get_pressed() == (0, 0, 0): self.hero.leftMousePressed = False if pygame.mouse.get_pressed() == (0, 0, 0): self.hero.rightMousePressed = False if __name__ == "__main__": game = GameMain() game.main_loop()So if anyone has an idea how I could fix this, I would be really grateful. Thank you for reading!