pythonooppygameshapesbulletphysics

Making bullets travel to cursor


I had an earlier post deleted because there are similar posts. I appreciate that but because I am so inexperienced with pygame (I literally began using it last week), I cant make heads or tails of the code. Also, I am finding it difficult to apply to my game. Firstly, I do not need it to relate to a moving player character as they will always travel from a set position (400, 450). Also, I preferably need it to do this when the left mouse button is pressed but if it is easier to use a key then that is fine. I simply do not have the expertise to use past posts and apply it to my program. Thanks. Just to clarify, my game is going to be a duck hunt-like target shooter game.


#Setting window dimensions and caption (Module 1)

pygame.init()
window = pygame.display.set_mode((800, 575))
pygame.display.set_caption("TARGET PRACTICE")

#Colour variables (Module 1)

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (200, 0, 0)
GREEN = (0, 200, 0)
BLUE = (0, 0, 200)


exec = True

#Target class created (Module 5)

class Target:
  def __init__(self, x, y, h, w, v):
    self.x = x
    self.y = y
    self.h = h
    self.w = w
    self.v = v


#Instantiation of targets (Module 5)

target_1 = Target(0, 80, 60, 40, 0.5)
target_2 = Target(0, 100, 60, 40, 0.5)
target_3 = Target(0, 50, 60, 40, 0.5)
target_4 = Target(0, 75, 60, 40, 0.5)
target_5 = Target(0, 45, 60, 40, 0.5)
target_6 = Target(0, 85, 60, 40, 0.5)


#Declaring variables to be used in the while loop (Module 5)
clock = 0

target_2_threshold = 500
target_3_threshold = 1000
target_4_threshold = 1500
target_5_threshold = 2000
target_6_threshold = 2500


#Setting player sprite dimension variables (Module 6)

player_sprite_x = 357.5
player_sprite_y = 450
player_sprite_h = 125
player_sprite_w = 85


while exec:
  pygame.time.delay(1)
  for event in pygame.event.get():
    if event.type == pygame.QUIT:
      exec = False


  #Defines movement of targets and sets delay between drawings (Module 5)   

  clock += 1
  target_1.x += target_1.v
  if clock > target_2_threshold:
        target_2.x += target_2.v
  if clock > target_3_threshold:
        target_3.x += target_3.v
  if clock > target_4_threshold:
        target_4.x += target_4.v
  if clock > target_5_threshold:
        target_5.x += target_5.v
  if clock > target_6_threshold:
        target_6.x += target_6.v

  #Fill the background (Module 5)

  window.fill(RED)

  #Redraw each target in every frame (Module 5)

  pygame.draw.rect(window, BLUE, (target_1.x, target_1.y, target_1.h, target_1.w))
  if clock > target_2_threshold:
      pygame.draw.rect(window, BLUE, (target_2.x, target_2.y, target_2.h, target_2.w)) 
  if clock > target_3_threshold:
      pygame.draw.rect(window, BLUE, (target_3.x, target_3.y, target_3.h, target_3.w))
  if clock > target_4_threshold:
      pygame.draw.rect(window, BLUE, (target_4.x, target_4.y, target_4.h, target_4.w))
  if clock > target_5_threshold:
      pygame.draw.rect(window, BLUE, (target_5.x, target_5.y, target_5.h, target_5.w))
  if clock > target_6_threshold:
      pygame.draw.rect(window, BLUE, (target_6.x, target_6.y, target_6.h, target_6.w))

  #Draw the player sprite (Module 6)

  pygame.draw.rect(window, BLUE, (player_sprite_x, player_sprite_y, player_sprite_w, player_sprite_h))

  pygame.display.update()


pygame.quit()

Solution

  • Use event pygame.MOUSEBUTTONDOWN to get mouse click and its position.

    You can use pygame.math.Vector2() to create vector between mouse and player. And then you can use normalize() to create value which you can use as bullet's direction.

    And keep in variable or list bullet's position and bullet's direction

    all_bullets = []
    
    while exec:
      pygame.time.delay(1)
      for event in pygame.event.get():
        if event.type == pygame.QUIT:
          exec = False
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                print("[shoot!] mouse position:", event.pos)
                dx = event.pos[0] - (player_sprite_x+ player_sprite_w//2)
                dy = event.pos[1] - player_sprite_y
                direction = pygame.math.Vector2(dx, dy).normalize()
                bullet = {'x': player_sprite_x+42, 'y': player_sprite_y, 'direction': direction}
                all_bullets.append(bullet)
    

    Later you can use for-loop to move every bullet on list and keep only bullets which are still on screen

      all_bullets_keep = []
    
      for item in all_bullets:
        item['x'] += item['direction'][0] # item['direction'][0] * 2
        item['y'] += item['direction'][1] # item['direction'][1] * 2
        # keep bullet if it is still on screen
        if 0 < item['x'] < 800 and 0 < item['y'] < 575:
              all_bullets_keep.append(item)
    
      all_bullets = all_bullets_keep
    
      #print(len(all_bullets), end='\r')
    

    Finally you can use for-loop to draw all bullets

      for item in all_bullets:
        pygame.draw.rect(window, BLUE, (item['x']-5, item['y']-5, 10, 10))
    

    It still need to check collision with targets but it would be easier if you would keep targets on list and use pygame.Rect()` to keep position and size because it has special methods to check collisions.

    So now you have work to use lists with tagets and pygame.Rect()


    import pygame
    
    
    
    pygame.init()
    window = pygame.display.set_mode((800, 575))
    pygame.display.set_caption("TARGET PRACTICE")
    
    #Colour variables (Module 1)
    
    BLACK = (0, 0, 0)
    WHITE = (255, 255, 255)
    RED = (200, 0, 0)
    GREEN = (0, 200, 0)
    BLUE = (0, 0, 200)
    
    
    exec = True
    
    #Target class created (Module 5)
    
    class Target:
      def __init__(self, x, y, h, w, v):
        self.x = x
        self.y = y
        self.h = h
        self.w = w
        self.v = v
    
    
    #Instantiation of targets (Module 5)
    
    target_1 = Target(0, 80, 60, 40, 0.5)
    target_2 = Target(0, 100, 60, 40, 0.5)
    target_3 = Target(0, 50, 60, 40, 0.5)
    target_4 = Target(0, 75, 60, 40, 0.5)
    target_5 = Target(0, 45, 60, 40, 0.5)
    target_6 = Target(0, 85, 60, 40, 0.5)
    
    
    #Declaring variables to be used in the while loop (Module 5)
    clock = 0
    
    target_2_threshold = 500
    target_3_threshold = 1000
    target_4_threshold = 1500
    target_5_threshold = 2000
    target_6_threshold = 2500
    
    
    #Setting player sprite dimension variables (Module 6)
    
    player_sprite_x = 357.5
    player_sprite_y = 450
    player_sprite_h = 125
    player_sprite_w = 85
    
    all_bullets = []
    
    while exec:
      pygame.time.delay(1)
      for event in pygame.event.get():
        if event.type == pygame.QUIT:
          exec = False
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                print("[shoot!] mouse position:", event.pos)
                dx = event.pos[0] - (player_sprite_x+ player_sprite_w//2)
                dy = event.pos[1] - player_sprite_y
                direction = pygame.math.Vector2(dx, dy).normalize()
                bullet = {'x': player_sprite_x+42, 'y': player_sprite_y, 'direction': direction}
                all_bullets.append(bullet)
    
      #Defines movement of targets and sets delay between drawings (Module 5)   
    
      clock += 1
      target_1.x += target_1.v
      if clock > target_2_threshold:
            target_2.x += target_2.v
      if clock > target_3_threshold:
            target_3.x += target_3.v
      if clock > target_4_threshold:
            target_4.x += target_4.v
      if clock > target_5_threshold:
            target_5.x += target_5.v
      if clock > target_6_threshold:
            target_6.x += target_6.v
    
      all_bullets_keep = []
    
      for item in all_bullets:
        item['x'] += item['direction'][0] # item['direction'][0] * 2
        item['y'] += item['direction'][1] # item['direction'][1] * 2
        # keep bullet if it is still on screen
        if 0 < item['x'] < 800 and 0 < item['y'] < 575:
              all_bullets_keep.append(item)
    
      all_bullets = all_bullets_keep
      #print(len(all_bullets), end='\r')
    
      #Fill the background (Module 5)
    
      window.fill(RED)
    
      #Redraw each target in every frame (Module 5)
    
      pygame.draw.rect(window, BLUE, (target_1.x, target_1.y, target_1.h, target_1.w))
      if clock > target_2_threshold:
          pygame.draw.rect(window, BLUE, (target_2.x, target_2.y, target_2.h, target_2.w)) 
      if clock > target_3_threshold:
          pygame.draw.rect(window, BLUE, (target_3.x, target_3.y, target_3.h, target_3.w))
      if clock > target_4_threshold:
          pygame.draw.rect(window, BLUE, (target_4.x, target_4.y, target_4.h, target_4.w))
      if clock > target_5_threshold:
          pygame.draw.rect(window, BLUE, (target_5.x, target_5.y, target_5.h, target_5.w))
      if clock > target_6_threshold:
          pygame.draw.rect(window, BLUE, (target_6.x, target_6.y, target_6.h, target_6.w))
    
      for item in all_bullets:
        pygame.draw.rect(window, BLUE, (item['x']-5, item['y']-5, 10, 10))
    
      #Draw the player sprite (Module 6)
    
      pygame.draw.rect(window, BLUE, (player_sprite_x, player_sprite_y, player_sprite_w, player_sprite_h))
    
      pygame.display.update()
    
    
    pygame.quit()