Reputation:
I just cant figure out why my bullet is not working. I made a bullet class and here it is:
class Bullet:
def __init__(self):
self.x = player.x
self.y = player.y
self.height = 7
self.width = 2
self.bullet = pygame.Surface((self.width, self.height))
self.bullet.fill((255, 255, 255))
Now I added several functions in my game class and here is the new code:
class Game:
def __init__(self):
self.bullets = []
def shoot_bullet(self):
if self.bullets:
for bullet in self.bullets:
rise = mouse.y - player.y
run = mouse.x - player.x
angle = math.atan2(rise, run)
bullet.x += math.cos(angle)
bullet.y += math.sin(angle)
pygame.transform.rotate(bullet.bullet, -math.degrees(angle))
D.blit(bullet.bullet, (bullet.x, bullet.y))
def generate_bullet(self):
if mouse.is_pressed():
self.bullets.append(Bullet())
What I was expecting the code to do was a Bullet()
would get added to game.bullets
every time I pressed the mouse button, then game.shoot_bullet
would calculate the angle between the player and the mouse and shoot the bullet accordingly in the direction of the mouse. However, the result is a complete mess and the bullets actually don't rotate and don't move. They get generated and move weirdly to the left of the screen. I am not sure if I have messed up something or the method I have used is completely wrong.
Upvotes: 7
Views: 4291
Reputation: 1
I noticed that the cycle where you checking the condition if lenghts is equal to 0 it doesn't really make any sense. Of-course the value of sqrt(0) is always 0, but how is this even possible in reality to get? 0% (i guess)
So, while its looking for a path by calculate a hypotenuse
if length == 0.0:
self.dir = (0, -1)
Upvotes: 0
Reputation: 210880
First of all pygame.transform.rotate
does not transform the object itself, but creates a new rotated surface and returns it.
If you want to fire a bullet in a certain direction, the direction is defined the moment the bullet is fired, but it does not change continuously. When the bullet is fired, set the starting position of the bullet and calculate the direction vector to the mouse position:
self.pos = (x, y)
mx, my = pygame.mouse.get_pos()
self.dir = (mx - x, my - y)
The direction vector should not depend on the distance to the mouse, but it has to be a Unit vector. Normalize the vector by dividing by the Euclidean distance
length = math.hypot(*self.dir)
if length == 0.0:
self.dir = (0, -1)
else:
self.dir = (self.dir[0]/length, self.dir[1]/length)
Compute the angle of the vector and rotate the bullet. In general, the angle of a vector can be computed by atan2(y, x)
. The y-axis needs to be reversed (atan2(-y, x)
) as the y-axis generally points up, but in the PyGame coordinate system the y-axis points down (see How to know the angle between two points?):
angle = math.degrees(math.atan2(-self.dir[1], self.dir[0]))
self.bullet = pygame.Surface((7, 2)).convert_alpha()
self.bullet.fill((255, 255, 255))
self.bullet = pygame.transform.rotate(self.bullet, angle)
To update the position of the bullet, it is sufficient to scale the direction (by a velocity) and add it to the position of the bullet:
self.pos = (self.pos[0]+self.dir[0]*self.speed,
self.pos[1]+self.dir[1]*self.speed)
To draw the rotated bullet in the correct position, take the bounding rectangle of the rotated bullet and set the center point with self.pos
(see How do I rotate an image around its center using PyGame?):
bullet_rect = self.bullet.get_rect(center = self.pos)
surf.blit(self.bullet, bullet_rect)
See also Shoot bullets towards target or mouse
Minimal example: repl.it/@Rabbid76/PyGame-FireBulletInDirectionOfMouse
import pygame
import math
pygame.init()
window = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()
class Bullet:
def __init__(self, x, y):
self.pos = (x, y)
mx, my = pygame.mouse.get_pos()
self.dir = (mx - x, my - y)
length = math.hypot(*self.dir)
if length == 0.0:
self.dir = (0, -1)
else:
self.dir = (self.dir[0]/length, self.dir[1]/length)
angle = math.degrees(math.atan2(-self.dir[1], self.dir[0]))
self.bullet = pygame.Surface((7, 2)).convert_alpha()
self.bullet.fill((255, 255, 255))
self.bullet = pygame.transform.rotate(self.bullet, angle)
self.speed = 2
def update(self):
self.pos = (self.pos[0]+self.dir[0]*self.speed,
self.pos[1]+self.dir[1]*self.speed)
def draw(self, surf):
bullet_rect = self.bullet.get_rect(center = self.pos)
surf.blit(self.bullet, bullet_rect)
bullets = []
pos = (250, 250)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
bullets.append(Bullet(*pos))
for bullet in bullets[:]:
bullet.update()
if not window.get_rect().collidepoint(bullet.pos):
bullets.remove(bullet)
window.fill(0)
pygame.draw.circle(window, (0, 255, 0), pos, 10)
for bullet in bullets:
bullet.draw(window)
pygame.display.flip()
Upvotes: 14