【问题标题】:Making bullets travel to cursor使子弹移动到光标
【发布时间】:2020-03-02 22:04:04
【问题描述】:

我删除了之前的帖子,因为有类似的帖子。我很感激,但是因为我对 pygame 非常缺乏经验(我实际上是上周开始使用它的),所以我无法确定代码的正面或反面。另外,我发现很难应用到我的游戏中。首先,我不需要它与移动的玩家角色相关,因为他们总是从设定的位置(400、450)移动。另外,当按下鼠标左键时,我最好需要它来执行此操作,但是如果使用键更容易,那很好。我根本不具备使用过去帖子并将其应用于我的程序的专业知识。谢谢。澄清一下,我的游戏将是一款类似于猎鸭的目标射击游戏。


#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()

【问题讨论】:

  • 与你之前的问题有什么不同? How can I make a bullet move to cursor position upon left click
  • 您想使用鼠标单击,但您甚至没有尝试在代码中使用pygame.MOUSEBUTTONDOWN。而且您的代码中没有向任何方向射击的子弹。
  • 顺便说一句:您可以将目标保留在列表中,然后您可以使用for-loop 来创建它们、移动它们、绘制它们并检查与项目符号的碰撞 - 代码会更短。跨度>
  • @Rabbid76 这个问题说明了我为什么转发。我真的不知道如何将这些其他解决方案应用于我的程序。我不懂语言。不要删除问题,也许人们可以建议不要使用光标瞄准,因为它太复杂了?

标签: python oop pygame shapes bulletphysics


【解决方案1】:

这里有一些简短的说明,可帮助您指明正确的方向。人们经常写出类似于“Gimme teh codez!”的问题,因此非常开放和广泛的问题通常会受到(非常正确地)消极的欢迎。

所以...

首先你需要抓住鼠标光标。这是通过在主事件循环中处理鼠标事件来实现的:

while exec:
    #pygame.time.delay(1)   # <-- DON'T DO THIS
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            exec = False
        elif event.type == pygame.MOUSEBUTTONUP:    # mouse button released
            mouse_position = pygame.mouse.get_pos()
            # TODO: handle mouse click at <mouse_position>

注意:我喜欢使用MOUSEBUTTONUP 而不是DOWN,因为这就是现代 GUI 的工作方式 - 屏幕上的操作会在发布时激活,但这取决于您。

现在你有了点击位置,如何从屏幕底部中心向鼠标坐标发射子弹?

首先,什么是底部中心?它是窗口宽度的一半,可能是底部的一些因素。在 PyGame 中,屏幕的左上角是(0, 0),左下角是( 0, window_height-1 )。我总是将窗口大小存储在变量中,因此计算这个位置很容易,并且如果窗口/屏幕大小发生变化,它就不必修改代码。

WINDOW_WIDTH  = 800
WINDOW_HEIGHT = 575

# Firing position is 98% bottom, middle of the window/screen.
start_position = ( ( WINDOW_WIDTH // 2,  int( WINDOW_HEIGHT * 0.98 ) )

然后单击鼠标,代码需要使子弹从start_position 移动到mouse_position。这可以通过计算出xy 速度来计算,每次更新都应应用于射弹。很明显,一个直线向下的弹丸的速度为( 0, something ),而一个直接向右的弹丸的速度为( something, 0 )。显然,如果向上或向左移动,something 将是负数,因为 PyGame 布局其坐标的方式。关键是变化有不同的组成部分:x 用于水平移动,y 用于垂直移动。

要计算 xy 速度(技术上是速度向量),代码需要确定从头到尾的线,然后 normalise 它(一种奇特的说法“除以它长度")。

我假设你已经知道line-length formula,所以这部分应该很简单。如果代码临时偏移两个点,就好像原点在(0,0),它会使计算更简单,因为方向仍然相同。

一旦代码有速度矢量(x, y),每个动画更新周期只需将这些组件速度添加到射弹的坐标。您可能需要将坐标存储为实数,因为向整数添加少量(例如:0.2)往往会丢弃更改。这是因为 some-integer + 0.2 -> some-integer.

不管怎样,看看你如何处理这些信息。如果问题仍然存在......再问一个问题!

【讨论】:

    【解决方案2】:

    使用事件pygame.MOUSEBUTTONDOWN 获取鼠标点击及其位置。

    您可以使用pygame.math.Vector2() 在鼠标和播放器之间创建矢量。然后您可以使用normalize() 来创建可以用作子弹方向的值。

    并保持变量或列出子弹的位置和子弹的方向

    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)
    

    稍后您可以使用for-loop 移动列表中的每个项目符号并仅保留仍在屏幕上的项目符号

      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')
    

    终于可以用for-loop 画出所有的子弹了

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

    它仍然需要检查与目标的碰撞,但如果你将目标保留在列表中并使用pygame.Rect()` 来保持位置和大小会更容易,因为它具有检查碰撞的特殊方法。

    所以现在你可以使用带有 tagets 和 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()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      相关资源
      最近更新 更多