[PyGame] Rotating image issue - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: Game Development (https://python-forum.io/forum-11.html) +--- Thread: [PyGame] Rotating image issue (/thread-21732.html) |
Rotating image issue - Evoluxman - Oct-11-2019 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: While i would like something like: 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! RE: Rotating image issue - metulburr - Oct-11-2019 I could take a look at it when I get back to a desk top. Until the it might be a good idea to upload the images or put your code online with the images. RE: Rotating image issue - Evoluxman - Oct-11-2019 (Oct-11-2019, 09:52 PM)metulburr Wrote: Until the it might be a good idea to upload the images or put your code online with the images. Sure, I host the project in private on Github if needed to, but aside from that, how could I upload you the code? RE: Rotating image issue - metulburr - Oct-11-2019 You can upload the 6 images on the forum. But it would be easier to just make your repo public and give us the link. Or imgur. Here is a tutorial of rotating via center https://python-forum.io/Thread-PyGame-Common-Tasks Sorry to be short. It's a pain in the ass on a phone. RE: Rotating image issue - Evoluxman - Oct-11-2019 Here is the repository, made public. Feel free to fork. The code to use is AntRot2.py [Link removed by user] And don't worry, I'm already more than happy to get some help with this. RE: Rotating image issue - Windspar - Oct-11-2019 Rotate an image in a circle. 1. Store center point. 2. Rotate from original image. 3. Get image new rect. 4. Set rect.center with store center. Also improve code. 1. Refactor Hero class. Its handling too much. 2. Learn to use pygame rects and vector2. 3. Your math can be made simpler. math.radians(angle) over angle * math.pi / 180 RE: Rotating image issue - Evoluxman - Oct-12-2019 Quote:1. Store center point. huuuh, I'm not so sure to what I have to do exactly. So in my init let's say I have self.master_image = pygame.image.load("Sprites/Ant-rot.png").convert_alpha() self.masterrect = self.master_image.get_rect(center=(75,75)) self.image = self.master_image.copy() self.rect = self.image.get_rect(center=(75,75))and in the update part self.image = pygame.transform.rotate(self.master_image, self.perso_angle) self.rect = self.image.get_rect(center=self.masterrect.center)when I do that my character is stuck on the right part of the screen. I'm quite lost on what I exactly have to do. Quote:Also improve code. yeah with each commit I try to remove/optimize useless/poorly written parts. If you had seen it when I first imported it from another code and then modified, I think you would have had a stroke ahaha. RE: Rotating image issue - Windspar - Oct-12-2019 Here an example. import os import pygame from pygame.sprite import Sprite from math import radians, sin, cos class Scene: def on_draw(self, surface): pass def on_event(self, event): pass def on_update(self, delta): pass class Manager: def __init__(self, caption, width, height, center=True): if center: os.environ['SDL_VIDEO_CENTERED'] = '1' # Basic pygame setup pygame.display.set_caption(caption) self.surface = pygame.display.set_mode((width, height)) self.rect = self.surface.get_rect() self.clock = pygame.time.Clock() self.running = False self.delta = 0 self.fps = 60 # Scene Interface self.scene = Scene() def mainloop(self): self.running = True while self.running: for event in pygame.event.get(): self.scene.on_event(event) self.scene.on_update(self.delta) self.scene.on_draw(self.surface) pygame.display.flip() self.delta = self.clock.tick(self.fps) class BaseSprite(Sprite): def __init__(self, image, position, anchor="topleft"): Sprite.__init__(self) self.original_image = image self.image = image self.rect = image.get_rect() setattr(self.rect, anchor, position) def draw(self, surface): surface.blit(self.image, self.rect) class RotationMovementKeys: def __init__(self, sprite, up, down, left, right): self.sprite = sprite self.up = up self.down = down self.left = left self.right = right self.angle = 0 self.speed = 0.04 self.rotation_speed = 0.08 self.center = pygame.Vector2(self.sprite.rect.center) self.set_direction() def set_direction(self): rad = radians(self.angle) self.direction = pygame.Vector2(sin(rad), cos(rad)) def do_rotate(self): self.sprite.image = pygame.transform.rotate(self.sprite.original_image, self.angle) self.sprite.rect = self.sprite.image.get_rect() self.sprite.rect.center = self.center self.set_direction() def on_keydown(self, keys_press, delta): if keys_press[self.up]: self.center -= self.direction * delta * self.speed self.sprite.rect.center = self.center elif keys_press[self.down]: self.center += self.direction * delta * (self.speed / 2) self.sprite.rect.center = self.center if keys_press[self.right]: self.angle = (self.angle - self.rotation_speed * delta) % 360 self.do_rotate() elif keys_press[self.left]: self.angle = (self.angle + self.rotation_speed * delta) % 360 self.do_rotate() class Example(Scene): def __init__(self, manager): self.create_image() self.manager = manager self.sprite = BaseSprite(self.rectangle, manager.rect.center, "center") self.sprite_movement = RotationMovementKeys(self.sprite, pygame.K_w, pygame.K_s, pygame.K_a, pygame.K_d) def create_image(self): self.rectangle = pygame.Surface((10, 20), pygame.SRCALPHA) self.rectangle.fill(pygame.Color('dodgerblue')) self.rectangle.fill(pygame.Color('white'), (2, 2, 6, 3)) def on_draw(self, surface): surface.fill(pygame.Color("black")) self.sprite.draw(surface) def on_event(self, event): if event.type == pygame.QUIT: self.manager.running = False def on_update(self, delta): keys = pygame.key.get_pressed() self.sprite_movement.on_keydown(keys, delta) def main(): pygame.init() manager = Manager("Rotation Example", 800, 600) manager.scene = Example(manager) manager.mainloop() if __name__ == "__main__": main() RE: Rotating image issue - Evoluxman - Oct-12-2019 Wow, that's a nice take! I will try to mod it to get back to what I had, and if I achieve it, I will set the thread solved. Thank you a lot! |