如何在 pygame 中向鼠标光标发射子弹
How to shoot a bullet towards mouse cursor in pygame
我正在尝试在 pygame 中创建一个自上而下的射击游戏。我想出了如何将子弹射向光标,但我的实现遇到了问题。当鼠标光标在玩家身上或非常靠近玩家时,射出的子弹非常慢。我不知道为什么。我该如何解决这个问题?
我的代码:
mouse_x, mouse_y = pygame.mouse.get_pos()
from_player_x, from_player_y = mouse_x - self.rect.x, mouse_y - self.rect.y
x_speed, y_speed = round(from_player_x * 0.1), round(from_player_y * 0.1)
self.speed_x = x_speed
self.speed_y = y_speed
...
self.rect.x += self.speed_x
self.rect.y += self.speed_y
要正确计算速度你不能直接使用from_player_x
和from_player_y
而是用它来计算angle
然后使用sin()
,cos()
计算 speed_x, speed_y
player = pygame.Rect(screen_rect.centerx, screen_rect.bottom, 0, 0)
SPEED = 5
#---
mouse_x, mouse_y = pygame.mouse.get_pos()
distance_x = mouse_x - player.x
distance_y = mouse_y - player.y
angle = math.atan2(distance_y, distance_x)
speed_x = SPEED * math.cos(angle)
speed_y = SPEED * math.sin(angle)
最小工作示例
import pygame
import math
# === CONSTANS === (UPPER_CASE names)
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 400
# === MAIN === (lower_case names)
# --- init ---
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
screen_rect = screen.get_rect()
# --- objects ---
player = pygame.Rect(screen_rect.centerx, screen_rect.bottom, 0, 0)
start = pygame.math.Vector2(player.center)
end = start
length = 50
SPEED = 5
all_bullets = []
# --- mainloop ---
clock = pygame.time.Clock()
is_running = True
while is_running:
# --- events ---
for event in pygame.event.get():
# --- global events ---
if event.type == pygame.QUIT:
is_running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
is_running = False
elif event.type == pygame.MOUSEMOTION:
mouse = pygame.mouse.get_pos()
end = start + (mouse - start).normalize() * length
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_x, mouse_y = pygame.mouse.get_pos()
distance_x = mouse_x - player.x
distance_y = mouse_y - player.y
angle = math.atan2(distance_y, distance_x)
# speed_x, speed_y can be `float` but I don't convert to `int` to get better position
speed_x = SPEED * math.cos(angle)
speed_y = SPEED * math.sin(angle)
# I copy `player.x, player.y` because I will change these values directly on list
all_bullets.append([player.x, player.y, speed_x, speed_y])
# --- objects events ---
# empty
# --- updates ---
# move using speed - I use indexes to change directly on list
for item in all_bullets:
# speed_x, speed_y can be `float` but I don't convert to `int` to get better position
item[0] += item[2] # pos_x += speed_x
item[1] += item[3] # pos_y -= speed_y
# --- draws ---
screen.fill(BLACK)
pygame.draw.line(screen, RED, start, end)
for pos_x, pos_y, speed_x, speed_y in all_bullets:
# need to convert `float` to `int` because `screen` use only `int` values
pos_x = int(pos_x)
pos_y = int(pos_y)
pygame.draw.line(screen, (0,255,0), (pos_x, pos_y), (pos_x, pos_y))
pygame.display.update()
# --- FPS ---
clock.tick(25)
# --- the end ---
pygame.quit()
PyGame有模块pygame.math and object Vector2可以让计算更简单
player = pygame.Rect(screen_rect.centerx, screen_rect.bottom, 0, 0)
start = pygame.math.Vector2(player.center)
SPEED = 5
# ---
mouse = pygame.mouse.get_pos()
distance = mouse - start
position = pygame.math.Vector2(start) # duplicate # start position in start of canon
#position = pygame.math.Vector2(end) # duplicate # start position in end of canon
speed = distance.normalize() * SPEED
以后
position += speed
最小工作示例
import pygame
# === CONSTANS === (UPPER_CASE names)
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 400
# === MAIN === (lower_case names)
# --- init ---
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
screen_rect = screen.get_rect()
# --- objects ---
player = pygame.Rect(screen_rect.centerx, screen_rect.bottom, 0, 0)
start = pygame.math.Vector2(player.center)
end = start
length = 50
SPEED = 5
all_bullets = []
# --- mainloop ---
clock = pygame.time.Clock()
is_running = True
while is_running:
# --- events ---
for event in pygame.event.get():
# --- global events ---
if event.type == pygame.QUIT:
is_running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
is_running = False
elif event.type == pygame.MOUSEMOTION:
mouse = pygame.mouse.get_pos()
end = start + (mouse - start).normalize() * length
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse = pygame.mouse.get_pos()
distance = mouse - start
position = pygame.math.Vector2(start) # duplicate # start position in start of canon
#position = pygame.math.Vector2(end) # duplicate # start position in end of canon
speed = distance.normalize() * SPEED
all_bullets.append([position, speed])
# --- objects events ---
# empty
# --- updates ---
for position, speed in all_bullets:
position += speed
# --- draws ---
screen.fill(BLACK)
pygame.draw.line(screen, RED, start, end)
for position, speed in all_bullets:
# need to convert `float` to `int` because `screen` use only `int` values
pos_x = int(position.x)
pos_y = int(position.y)
pygame.draw.line(screen, (0,255,0), (pos_x, pos_y), (pos_x, pos_y))
pygame.display.update()
# --- FPS ---
clock.tick(25)
# --- the end ---
pygame.quit()
我正在尝试在 pygame 中创建一个自上而下的射击游戏。我想出了如何将子弹射向光标,但我的实现遇到了问题。当鼠标光标在玩家身上或非常靠近玩家时,射出的子弹非常慢。我不知道为什么。我该如何解决这个问题?
我的代码:
mouse_x, mouse_y = pygame.mouse.get_pos()
from_player_x, from_player_y = mouse_x - self.rect.x, mouse_y - self.rect.y
x_speed, y_speed = round(from_player_x * 0.1), round(from_player_y * 0.1)
self.speed_x = x_speed
self.speed_y = y_speed
...
self.rect.x += self.speed_x
self.rect.y += self.speed_y
要正确计算速度你不能直接使用from_player_x
和from_player_y
而是用它来计算angle
然后使用sin()
,cos()
计算 speed_x, speed_y
player = pygame.Rect(screen_rect.centerx, screen_rect.bottom, 0, 0)
SPEED = 5
#---
mouse_x, mouse_y = pygame.mouse.get_pos()
distance_x = mouse_x - player.x
distance_y = mouse_y - player.y
angle = math.atan2(distance_y, distance_x)
speed_x = SPEED * math.cos(angle)
speed_y = SPEED * math.sin(angle)
最小工作示例
import pygame
import math
# === CONSTANS === (UPPER_CASE names)
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 400
# === MAIN === (lower_case names)
# --- init ---
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
screen_rect = screen.get_rect()
# --- objects ---
player = pygame.Rect(screen_rect.centerx, screen_rect.bottom, 0, 0)
start = pygame.math.Vector2(player.center)
end = start
length = 50
SPEED = 5
all_bullets = []
# --- mainloop ---
clock = pygame.time.Clock()
is_running = True
while is_running:
# --- events ---
for event in pygame.event.get():
# --- global events ---
if event.type == pygame.QUIT:
is_running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
is_running = False
elif event.type == pygame.MOUSEMOTION:
mouse = pygame.mouse.get_pos()
end = start + (mouse - start).normalize() * length
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_x, mouse_y = pygame.mouse.get_pos()
distance_x = mouse_x - player.x
distance_y = mouse_y - player.y
angle = math.atan2(distance_y, distance_x)
# speed_x, speed_y can be `float` but I don't convert to `int` to get better position
speed_x = SPEED * math.cos(angle)
speed_y = SPEED * math.sin(angle)
# I copy `player.x, player.y` because I will change these values directly on list
all_bullets.append([player.x, player.y, speed_x, speed_y])
# --- objects events ---
# empty
# --- updates ---
# move using speed - I use indexes to change directly on list
for item in all_bullets:
# speed_x, speed_y can be `float` but I don't convert to `int` to get better position
item[0] += item[2] # pos_x += speed_x
item[1] += item[3] # pos_y -= speed_y
# --- draws ---
screen.fill(BLACK)
pygame.draw.line(screen, RED, start, end)
for pos_x, pos_y, speed_x, speed_y in all_bullets:
# need to convert `float` to `int` because `screen` use only `int` values
pos_x = int(pos_x)
pos_y = int(pos_y)
pygame.draw.line(screen, (0,255,0), (pos_x, pos_y), (pos_x, pos_y))
pygame.display.update()
# --- FPS ---
clock.tick(25)
# --- the end ---
pygame.quit()
PyGame有模块pygame.math and object Vector2可以让计算更简单
player = pygame.Rect(screen_rect.centerx, screen_rect.bottom, 0, 0)
start = pygame.math.Vector2(player.center)
SPEED = 5
# ---
mouse = pygame.mouse.get_pos()
distance = mouse - start
position = pygame.math.Vector2(start) # duplicate # start position in start of canon
#position = pygame.math.Vector2(end) # duplicate # start position in end of canon
speed = distance.normalize() * SPEED
以后
position += speed
最小工作示例
import pygame
# === CONSTANS === (UPPER_CASE names)
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 400
# === MAIN === (lower_case names)
# --- init ---
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
screen_rect = screen.get_rect()
# --- objects ---
player = pygame.Rect(screen_rect.centerx, screen_rect.bottom, 0, 0)
start = pygame.math.Vector2(player.center)
end = start
length = 50
SPEED = 5
all_bullets = []
# --- mainloop ---
clock = pygame.time.Clock()
is_running = True
while is_running:
# --- events ---
for event in pygame.event.get():
# --- global events ---
if event.type == pygame.QUIT:
is_running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
is_running = False
elif event.type == pygame.MOUSEMOTION:
mouse = pygame.mouse.get_pos()
end = start + (mouse - start).normalize() * length
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse = pygame.mouse.get_pos()
distance = mouse - start
position = pygame.math.Vector2(start) # duplicate # start position in start of canon
#position = pygame.math.Vector2(end) # duplicate # start position in end of canon
speed = distance.normalize() * SPEED
all_bullets.append([position, speed])
# --- objects events ---
# empty
# --- updates ---
for position, speed in all_bullets:
position += speed
# --- draws ---
screen.fill(BLACK)
pygame.draw.line(screen, RED, start, end)
for position, speed in all_bullets:
# need to convert `float` to `int` because `screen` use only `int` values
pos_x = int(position.x)
pos_y = int(position.y)
pygame.draw.line(screen, (0,255,0), (pos_x, pos_y), (pos_x, pos_y))
pygame.display.update()
# --- FPS ---
clock.tick(25)
# --- the end ---
pygame.quit()