让子弹移动到光标
Making bullets travel to cursor
我删除了较早的 post,因为有类似的 post。我很感激,但是因为我对 pygame 没有经验(我上周才真正开始使用它),所以我无法理解代码的正反两面。另外,我发现很难应用到我的游戏中。首先,我不需要它与移动的玩家角色相关,因为他们总是从设定位置 (400, 450) 移动。另外,我最好在按下鼠标左键时需要它来执行此操作,但如果使用按键更容易,那也没关系。我根本不具备使用过去的 post 并将其应用于我的程序的专业知识。谢谢。澄清一下,我的游戏将是一款类似猎鸭的目标射击游戏。
#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()
使用事件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
循环绘制所有子弹了
for item in all_bullets:
pygame.draw.rect(window, BLUE, (item['x']-5, item['y']-5, 10, 10))
它仍然需要检查与目标的碰撞,但如果您将目标保留在列表中并使用 pygame.Rect()` 来保持位置和大小会更容易,因为它有特殊的方法来检查碰撞。
所以现在您可以使用带有目标和 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()
这里有一些简短的注释,可以帮助您指明正确的方向。人们经常写下类似“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 的工作方式 - 屏幕操作在发布时激活,但这取决于你。
现在你有了点击位置,你如何从屏幕底部中心到鼠标坐标发射子弹?
那么,首先什么是bottom-center?它是 window 宽度的一半,可能是底部的一些因素。在PyGame中,屏幕的左上角是(0, 0)
,左下角是( 0, window_height-1 )
。我 总是 将 window 大小存储在变量中,因此计算这个位置很容易,并且如果 window/screen 大小发生变化,它就不必修改代码。
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
。这可以通过计算 x
和 y
速度来计算,每次更新时,应将其应用于射弹。显然,直线向下的弹丸速度为( 0, something )
,而直线向右的弹丸速度为( something, 0 )
。显然,如果向上或向左移动,something 将是负数,因为 PyGame 布置其坐标的方式。关键是变化有不同的组成部分:x
用于水平移动,y
用于垂直移动。
要计算此 x
和 y
速度(技术上是速度矢量),代码需要确定从头到尾的直线,然后 normalise 它(花哨的"divide it by it's length").
的表达方式
我假设您已经知道 line-length formula,所以这部分应该很简单。如果代码暂时偏移两个点,就好像原点在 (0,0)
,因为方向仍然相同,这会使计算更简单。
一旦代码具有速度矢量 (x, y)
,每个动画更新周期只需将这些组件速度添加到射弹的坐标。您可能需要将坐标存储为实数,因为向整数添加少量(例如:0.2
)往往会丢弃更改。这是因为 some-integer + 0.2 -> some-integer.
无论如何,看看你如何处理这些信息。如果问题仍然存在...再问一个问题!
我删除了较早的 post,因为有类似的 post。我很感激,但是因为我对 pygame 没有经验(我上周才真正开始使用它),所以我无法理解代码的正反两面。另外,我发现很难应用到我的游戏中。首先,我不需要它与移动的玩家角色相关,因为他们总是从设定位置 (400, 450) 移动。另外,我最好在按下鼠标左键时需要它来执行此操作,但如果使用按键更容易,那也没关系。我根本不具备使用过去的 post 并将其应用于我的程序的专业知识。谢谢。澄清一下,我的游戏将是一款类似猎鸭的目标射击游戏。
#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()
使用事件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
循环绘制所有子弹了
for item in all_bullets:
pygame.draw.rect(window, BLUE, (item['x']-5, item['y']-5, 10, 10))
它仍然需要检查与目标的碰撞,但如果您将目标保留在列表中并使用 pygame.Rect()` 来保持位置和大小会更容易,因为它有特殊的方法来检查碰撞。
所以现在您可以使用带有目标和 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()
这里有一些简短的注释,可以帮助您指明正确的方向。人们经常写下类似“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 的工作方式 - 屏幕操作在发布时激活,但这取决于你。
现在你有了点击位置,你如何从屏幕底部中心到鼠标坐标发射子弹?
那么,首先什么是bottom-center?它是 window 宽度的一半,可能是底部的一些因素。在PyGame中,屏幕的左上角是(0, 0)
,左下角是( 0, window_height-1 )
。我 总是 将 window 大小存储在变量中,因此计算这个位置很容易,并且如果 window/screen 大小发生变化,它就不必修改代码。
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
。这可以通过计算 x
和 y
速度来计算,每次更新时,应将其应用于射弹。显然,直线向下的弹丸速度为( 0, something )
,而直线向右的弹丸速度为( something, 0 )
。显然,如果向上或向左移动,something 将是负数,因为 PyGame 布置其坐标的方式。关键是变化有不同的组成部分:x
用于水平移动,y
用于垂直移动。
要计算此 x
和 y
速度(技术上是速度矢量),代码需要确定从头到尾的直线,然后 normalise 它(花哨的"divide it by it's length").
我假设您已经知道 line-length formula,所以这部分应该很简单。如果代码暂时偏移两个点,就好像原点在 (0,0)
,因为方向仍然相同,这会使计算更简单。
一旦代码具有速度矢量 (x, y)
,每个动画更新周期只需将这些组件速度添加到射弹的坐标。您可能需要将坐标存储为实数,因为向整数添加少量(例如:0.2
)往往会丢弃更改。这是因为 some-integer + 0.2 -> some-integer.
无论如何,看看你如何处理这些信息。如果问题仍然存在...再问一个问题!