Tank Movement in Pygame
Published: 2024-01-04 20:34:45

Play Toy Tanks [Here](https://github.com/Hessler5/Toys-Tanks)

For my phase 3 project at the Flatiron School I decided to make a tank game using the Pygame modules. This being the first game I have ever made there was quite a learning curve and I want to document some of the challenges I encountered regarding rotation and angular movement and how I solved for them.

**Tank Rotation**
Quickly upon diving into video game movement I realized moving a tank would be a tougher task then your average 2-D sidescroller. This being due to the fact tanks have to rotate 360 degrees and can move along any one of these angles. The first thing I tackled was rotating the tank Image. Un-intutivly when I used the pygame.transoform.rotate() method on my image it did not achieve the the results I intend. If you just use pygame.transoform.rotate() your image will appear to bounce around inside of a box because pygame is not keeping the center coordinates of the image the same post rotation.
 

As can be seen in the below images as you rotate the tanks image 30 degrees the center point illustrated as the blue dot is not consistent. Also not the expansion and contraction of the image rect as the tank rotates illustrated in green.

![Tank Rotated 0 degrees without center update](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ltkd3589qpq64a6i5g3v.png)
![Tank Rotated 30 degrees without center update](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kn6ii105mxne0egia661.png)
![Tank Rotated 60 degrees without center update](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6xwjn8tm6ibkj8z2ykqh.png)
![Tank Rotated 90 degrees without center update](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vt7gy7jy0pchj8v42u8w.png)



The way I fixed this was creating a source of truth image that never gets drawn but is used to create a source of truth rect. Every time the rotated image gets rotated you updated the center of the updated images rect to be the center of the source of truth rect. Then you blit the rotated image to the screen with the rotated rect. That way the tank always appears to spin around the same point. As an added note as the tank moves around the screen I made sure to updated the position on both the source of truth rect and the the rotated rect so that the centers of the two rects would stay consistent. 

Below is the tank rotating 30 degrees again but with the center updated every rotation. 

![Tank Rotated 0 degrees with center update](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x821dzpyg79pe8z2jdcs.png)
![Tank Rotated 30 degrees with center update](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2lh6juwu9lbf3ncyt0ne.png)
![Tank Rotated 60 degrees with center update](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f3k1716pa1a420n97mnl.png)
![Tank Rotated 90 degrees with center update](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gls2nee8qzo6mkmdouaj.png)
**Tank Movement**
After figuring out rotation I tackled the movement. In a typical top down game movement is fairly straight forward, for up/down movement increment the Y cord and for left/right increment the x cord. However when moving at a 35% angle form the origin with a velocity of for example 1 how much do you increment x and Y? This is where trigonometry comes in but luckily pyagme has some built in tools to help with the math. 

Pygame.Vector2() is what I used to make the tank movement trivial. I wont attempt to define a vector here as there are much better sources online but for the purposes of this blog a vector is just a (x, y) coordinate that when compared to the origin (0, 0) you can draw an arrow showing both distance and direction. Along with pygame.Vector2() you can use the .rotate(angle) method which will rotate you vector for you without having to do the math yourself. So if you create a vector where x is 0 and Y is your forward velocity. Then rotate the vector by the current rotation of the tank you will get the corresponding x and Y increments. You can then add this onto the center coordinate of the rectangle you are using to blit your tank to the screen and presto your tank will be moving in the appropriate direction! [Here](https://stackoverflow.com/questions/61106297/moving-forward-after-angle-change-pygame) is a great Stack Overflow response that helped me understand this topic.

The circle around the tank in the below image shows the incremental distance the tank can travel in at any angle. The black dot illustrates a radian of (0, velocity). The green dot show the radian updated for a rotation of 30 degrees. If you then add the x of the new radian to the x cord of the tank center and likewise for y the tank will move in the appropriate direction.
![vector illustration](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hhap6dnkq3q3clarlaeo.png)


**A Few Added Notes**
If you want your tank to shoot in the angle you are facing you would use the same logic as how you moved the tank. If you want your bullet to bounce off things just track the x and y collision separately. If x collides multiply the x vector cord by a value of -1 and likewise for the y.

I would strongly encourage any one making a tank game to use a mask for collision detection on the tank. I wont go into how to use masks in this blog but [here](https://www.youtube.com/watch?v=tJiKYMQJnYg&ab_channel=CodingWithRuss) is a great Youtube video I used to understand them. If you use the rect of a rotated tank instead of a mask for collision your tanks hit box will be enlarged when the tank is rotated as illustrated above and it will make movement and hit detection very clunky.