Rotating an Image using an arbitrary pivot point, with PyGame
Introduction
Rotation is everywhere, and you can use it in many, many scenarios. A ball, a falling structure, a projectile, etc.
The case study for this tutorial is the Blue Sword the player can use to put mobs down. As you can see the image above is the initial state, where the sword remains vertical right next to the player. When the player presses the space bar the sword starts brandishing until it completes a 170 degrees movement:
Once that position is reached, the sword starts its way back to the initial state.
Background
PyGame provides a method to rotate a surface using its center as the rotation point (Rotation axis) which we are going to rely on.
There's something you need to consider when doing this kind of transformations, in particular in this case where we want to apply it several times, it distorts the image a little bit each time, so if we preserve the rotated surface on each step we'll end up with a very noisy result.
To avoid this, we'll only preserve the original surface and apply a rotation with an increasing angle each step to that surface, discarding the previously rotated one.
Implementation
The rotation itself is pretty easy and can be done this way:
angle = 1 # In Degrees # Create the surface sword_surface = pygame.image.load(PATH_TO_IMAGE) # Rotate the surface rotated_sword_surface = pygame.transform.rotate(sword_surface, angle) angle += 1
We will do this, for example, inside the `update` method that's called once per iteration of the main loop. So you'll need to save the value of `angle` somewhere.
This approach has a flaw, which is that the surface is being rotated using the surface's center as the rotation point, as I said before. The result looks quite weird to the eye:
To create a more "natural" movement we need to rotate the sword using a point near the sword's grip.
For this, we need to create a new vector called "rotation_vector" which starts at the pivot point and points to the surface's center. We are going to rotate this vector the same degrees as the surface, using a Vector2 instance and a Vector2's method called "rotate". Once that vector is rotated, we relocate the surface's center to the vector's X and Y.
The code looks like this:
angle = 1 # In Degrees pivot = Vector2(p_x, p_y) # You can use any X and Y here. # Create the surface sword_surface = pygame.image.load(PATH_TO_IMAGE) sword_rect = sword_surface.get_rect() # Create the rotation vector rotation_vector = sword_surface.get_rect().center - pivot # Rotate the rotation vector, and store as a new variable rotated_vector = rotation_vector.rotate(angle) # Rotate the surface rotated_sword_surface = pygame.transform.rotate(sword_surface, angle) # Relocate the surface relocation_vector = rotated_vector - rotation_vector sword_rect.center += relocation_vector self.image = sword_surface self.rect = sword_rect angle += 1
That should do the trick!
Any feedback or correction let me know in the comments. :)
Get The Alchemist
The Alchemist
Things went wrong on the alchemist's house, help him overcome this situation!
More posts
- Version 1.4 released! Levels and new Enemies!Apr 02, 2021
- Hackable levels: 1.4 PreviewMar 23, 2021
- Particles & Grayscale with Pygame and NumpyMar 09, 2021
- Red Challenge: Watch me fail over and over again ~.~Mar 04, 2021
- Version 1.3.5: Banishing VFX/SFX for mobsMar 02, 2021
- Version 1.3.4 Available! new UI and better mechanicsFeb 24, 2021
- Python 3.9.2 available for download!Feb 20, 2021
- Dynamically sized frame box with PyGame: Am I framing everything? YesFeb 19, 2021
- Next steps... Let's walkFeb 17, 2021
- Version 1.3.3 Available! New Mobs, Friction, Swords, and more...Feb 15, 2021
Leave a comment
Log in with itch.io to leave a comment.