pygame 中敌人朝玩家的二维运动,如何计算 x 和 y 速度?
- 2025-02-28 08:24:00
- admin 原创
- 77
问题描述:
在我正在制作的游戏中,我需要让敌人向玩家移动(这里敌人是一团)为了实现这一点,我已经创建了一个函数:def calculate_enemy_movement(enemy):
并且在它里面我放入了函数需要做的事情:
计算每帧需要添加多少 x 值(x 速度),以及每帧需要添加多少 y 值(y 速度)
enemy.x
才能enemy.y
走向player.x
andplayer.y
,然后返回 x 速度并返回 y 速度。此函数在此处调用:每帧将 x 速度和 y 速度添加到敌人的 x 和 y 位置
enemy_blob.x,enemy_blob.y += calculate_enemy_movement(enemy_blob)
现在我只需要有人帮我创建这个函数。我已经研究过了,我知道它与矢量数学有关,但我不确定它的具体工作原理,所以如果有人能编写这个函数并向我解释它的工作原理,我会非常高兴。
如果您需要其余代码:
import pygame
import os
import sys
from math import *
import math
from typing import Tuple
from pygame.locals import *
running = False
class Game():
def __init__(self):
main()
pygame.init()
FPS = 60
ani = 4
def diagonal_x_vel(velocity):
diagonal_x = int((math.pi / 4) * velocity)
return diagonal_x
def diagonal_y_vel(velocity):
diagonal_y = int(sin(math.pi / 4) * velocity)
return diagonal_y
def move(rect, movement):
global player_rect
rect.x += movement[0]
rect.y += movement[1]
return rect
WIDTH, HEIGHT = 1920, 1080
player_action = "idle"
player_frame = 0
class Player():
def __init__(self):
self.main_char_height, self.main_char_width = 35 * 4, 35 * 4
self.main_char_x = WIDTH / 2 - self.main_char_width / 2
self.main_char_y = HEIGHT / 2 - self.main_char_height / 2
self.current_health = 80
self.maximum_health = 100
self.health_bar_length = 500
self.health_ratio = self.maximum_health / self.health_bar_length
self.moving_right, self.moving_left, self.moving_down, self.moving_up, self.idle = False, False, False, False, True
self.player_rect = pygame.Rect(self.main_char_x, self.main_char_y, self.main_char_width, self.main_char_height)
self.player_flip = False
self.VEL = 8
def update():
pass
def take_dmg(self, amount):
if self.current_health > 0:
self.current_health -= amount
if self.current_health <= 0:
self.current_health = 0
def get_health(self, amount):
if self.current_health < self.maximum_health:
self.current_health += amount
if self.current_health >= self.maximum_health:
self.current_health = self.maximum_health
class Enemy():
def __init__(self, health, attack_damage, raw_speed, x, y, height, width, action,diagonal_vel_x,diangonal_vel_y):
self.x = x
self.y = y
self.health = health
self.attack_damage = attack_damage
self.speed = raw_speed
self.enemy_rect = pygame.Rect(x,y,width,height)
self.action = action
WIN = pygame.display.set_mode([WIDTH, HEIGHT], pygame.FULLSCREEN)
pygame.display.set_caption("first game")
player = Player()
animation_frames = {}
def load_animation(path, image_name, frame_duration, scale_width, scale_height):
global animation_frames
animation_frame_data = []
n = 0
for frame in frame_duration:
animation_frame_id = image_name + "_" + str(n)
img_loc = path + "/" + animation_frame_id + ".png"
animation_image = pygame.transform.scale(pygame.image.load(img_loc),
(scale_width, scale_height)).convert_alpha()
animation_image.convert()
animation_frames[animation_frame_id] = animation_image.copy()
for i in range(frame):
animation_frame_data.append(animation_frame_id)
n += 1
return animation_frame_data
def change_action(action_var, frame, new_value):
if action_var != new_value:
action_var = new_value
return action_var, frame
animation_database = {}
animation_database["idle"] = load_animation("assets", "darkpurpleknight_idle", [8, 8, 8, 8], player.main_char_width,
player.main_char_height)
animation_database["run_top"] = load_animation("assets", "darkpurpleknight_run_up", [8, 8, 8, 8, 8, 8],
player.main_char_width,
player.main_char_height)
animation_database["run_bot"] = load_animation("assets", "darkpurpleknight_run_down", [8, 8, 8, 8, 8, 8],
player.main_char_width, player.main_char_height)
animation_database["run"] = load_animation("assets", "darkpurpleknight_run", [8, 8, 8, 8, 8, 8], player.main_char_width,
player.main_char_height)
scroll = [0, 0]
blob_height = 17
blob_width = 25
blob_frame = 0
enemy_blob = Enemy(50, 10, 5, 1000 , 1000, 17, 25, "blob_idle",0,0)
animation_database["blob_idle"] = load_animation("assets", "blob_idle", [30, 30], blob_width * 4, blob_height * 4)
clock = pygame.time.Clock()
def collision(rectA, rectB):
if rectB.right < rectA.left:
# rectB est à gauche
return False
if rectB.bottom < rectA.top:
# rectB est au-dessus
return False
if rectB.left > rectA.right:
# rectB est à droite
return False
if rectB.top > rectA.bottom:
# rectB est en-dessous
return False
elif rectB.right > rectA.left:
# rectB est en collision avec la gauche
return True
elif rectB.bottom < rectA.top:
# rectB est en collision avec le haut
return True
elif rectB.left > rectA.right:
# rectB est en collision avec la droite
return True
elif rectB.top > rectA.bottom:
# rectB est en collision avec le bas
return True
bg_img = pygame.transform.scale(pygame.image.load("assets/DUNGEON_PISKEL_REMAKE_WITH_WALL_PROPS-1.png"),
(WIDTH * 2, HEIGHT * 2)).convert()
def animate_sprite(frame_counter, action):
global animation_database
frame_counter += 1
if frame_counter >= len(animation_database[action]):
frame_counter = 0
img_id = animation_database[action][frame_counter]
animated_image = animation_frames[img_id]
return animated_image, frame_counter
#def calculate_enemy_movement(enemy):
#calculate what x value needs to be added each frame(x velocity), and what y value needs to be added each frame(y velocity) to the enemy.x and enemy.y to walk
#towards the player.x and player.y.
#return x velocity and return y velocity
def draw_window(window):
global enemy_blob
window = window
global main_char_x, main_char_y
global player_frame, bg_img, blob_frame
global scroll
global slide
#add x velocity and y velocity to x and y pos of enemy each frame
#enemy_blob.x,enemy_blob.y += calculate_enemy_movement(enemy_blob)
window.blit(bg_img, (-WIDTH / 2 - scroll[0], -HEIGHT / 2 - scroll[1]))
blob_img, blob_frame = animate_sprite(blob_frame, enemy_blob.action)
window.blit(blob_img, (enemy_blob.x - scroll[0], enemy_blob.y - scroll[1]))
player_img, player_frame = animate_sprite(player_frame, player_action)
window.blit(pygame.transform.flip(player_img, player.player_flip, False), (player.player_rect.x, player.player_rect.y))
pygame.display.update()
borders = []
coliding = False
def set_borders(x, y, width, height):
border = pygame.Rect((x, y), (width, height))
return border
def check_colision(target, list):
is_coliding = []
for i in list:
is_coliding.append(collision(i, target))
return is_coliding
def main():
global scroll
global player_frame
global player_action
global player_flip
global player_rect, rect1, coliding
global VEL
global top_wall
global borders
global main_char_x, main_char_y
global moving_left, moving_right, moving_up, moving_down, idle
game_running = True
while game_running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == K_ESCAPE:
game_running = False
from start_menu import Open_launcher
Open_launcher()
sys.exit()
top_map_border = set_borders(-WIDTH / 2 - scroll[0], -HEIGHT / 2 + 250 - scroll[1], 5000, 1)
bot_map_border = set_borders(-WIDTH / 2 - scroll[0], HEIGHT + 355 - scroll[1], 5000, 1)
left_map_border = set_borders(-WIDTH / 2 + 160 - scroll[0], -HEIGHT / 2 - scroll[1], 1, 5000)
right_map_border = set_borders(WIDTH + 785 - scroll[0], -HEIGHT / 2 + 150 - scroll[1], 1, 5000)
borders = [top_map_border, bot_map_border, left_map_border, right_map_border]
enemies = []
is_coliding_with_borders = check_colision(player.player_rect, borders)
is_coliding_with_enemy = check_colision(player.player_rect, enemies)
top_coliding = is_coliding_with_borders[0]
bot_coliding = is_coliding_with_borders[1]
left_coliding = is_coliding_with_borders[2]
right_coliding = is_coliding_with_borders[3]
keys = pygame.key.get_pressed()
# EVERY MOVEMENT THAT USES "A"
if keys[pygame.K_a]:
# DIAGONAL TOP LEFT
if keys[pygame.K_w] and not keys[pygame.K_d]:
if not left_coliding and not top_coliding:
player.player_flip = True
player_action, player_frame = change_action(player_action, player_frame, "run")
scroll[0] -= diagonal_x_vel(player.VEL)
scroll[1] -= diagonal_y_vel(player.VEL)
elif left_coliding and not top_coliding:
player.player_flip = True
scroll[1] -= player.VEL
player_action, player_frame = change_action(player_action, player_frame, "run_top")
elif top_coliding and not left_coliding:
player.player_flip = True
scroll[0] -= player.VEL
player_action, player_frame = change_action(player_action, player_frame, "run")
elif left_coliding and top_coliding:
player.player_flip = False
player_action, player_frame = change_action(player_action, player_frame, "idle")
# DIAGONAL BOT LEFT
elif keys[pygame.K_s] and not keys[pygame.K_d]:
if not left_coliding and not bot_coliding:
player.player_flip = True
player_action, player_frame = change_action(player_action, player_frame, "run")
scroll[0] -= diagonal_x_vel(player.VEL)
scroll[1] += diagonal_y_vel(player.VEL)
elif left_coliding and not bot_coliding:
player.player_flip = True
scroll[1] += player.VEL
player_action, player_frame = change_action(player_action, player_frame, "run_bot")
elif not left_coliding and bot_coliding:
player.player_flip = True
scroll[0] -= player.VEL
player_action, player_frame = change_action(player_action, player_frame, "run")
elif left_coliding and bot_coliding:
player.player_flip = False
player_action, player_frame = change_action(player_action, player_frame, "idle")
# LEFT MOVEMENT
elif not keys[pygame.K_s] and not keys[pygame.K_d] and not keys[pygame.K_w]:
if not left_coliding:
player.player_flip = True
scroll[0] -= player.VEL
player_action, player_frame = change_action(player_action, player_frame, "run")
else:
player.player_flip = True
player_action, player_frame = change_action(player_action, player_frame, "run")
else:
player_action, player_frame = change_action(player_action, player_frame, "idle")
# EVERY MOVEMENT THAT USES "D"
if keys[pygame.K_d]:
# DIAGONAL TOP RIGHT
if keys[pygame.K_w] and not keys[pygame.K_a] and not keys[pygame.K_s]:
if not right_coliding and not top_coliding:
player.player_flip = False
player_action, player_frame = change_action(player_action, player_frame, "run")
scroll[0] += diagonal_x_vel(player.VEL)
scroll[1] -= diagonal_y_vel(player.VEL)
elif right_coliding and not top_coliding:
player.player_flip = False
scroll[1] -= player.VEL
player_action, player_frame = change_action(player_action, player_frame, "run_top")
elif top_coliding and not right_coliding:
player.player_flip = False
scroll[0] += player.VEL
player_action, player_frame = change_action(player_action, player_frame, "run")
elif right_coliding and top_coliding:
player.player_flip = False
player_action, player_frame = change_action(player_action, player_frame, "idle")
# DIAGONAL BOT RIGHT
elif keys[pygame.K_s] and not keys[pygame.K_a] and not keys[pygame.K_w]:
if not right_coliding and not bot_coliding:
player.player_flip = False
player_action, player_frame = change_action(player_action, player_frame, "run")
scroll[0] += diagonal_x_vel(player.VEL)
scroll[1] += diagonal_y_vel(player.VEL)
elif right_coliding and not bot_coliding:
player.player_flip = False
scroll[1] += player.VEL
player_action, player_frame = change_action(player_action, player_frame, "run_bot")
elif not right_coliding and bot_coliding:
player.player_flip = False
scroll[0] += player.VEL
player_action, player_frame = change_action(player_action, player_frame, "run")
elif right_coliding and bot_coliding:
player.player_flip = False
player_action, player_frame = change_action(player_action, player_frame, "idle")
# RIGHT MOVEMENT
elif not keys[pygame.K_s] and not keys[pygame.K_a] and not keys[pygame.K_w]:
if not right_coliding:
player.player_flip = False
scroll[0] += player.VEL
player_action, player_frame = change_action(player_action, player_frame, "run")
else:
player.player_flip = False
player_action, player_frame = change_action(player_action, player_frame, "run")
else:
player_action, player_frame = change_action(player_action, player_frame, "idle")
# EVERY MOVEMENT THAT USES "W"
if keys[pygame.K_w]:
# UP MOVEMENT
if not keys[pygame.K_d] and not keys[pygame.K_a]:
if not top_coliding:
player_action, player_frame = change_action(player_action, player_frame, "run_top")
scroll[1] -= player.VEL
else:
player_action, player_frame = change_action(player_action, player_frame, "run_top")
# EVERY MOVEMENT THAT USES "S"
if keys[pygame.K_s]:
# DOWN MOVEMENT
if not keys[pygame.K_d] and not keys[pygame.K_a]:
if not bot_coliding:
player_action, player_frame = change_action(player_action, player_frame, "run_bot")
scroll[1] += player.VEL
else:
player_action, player_frame = change_action(player_action, player_frame, "run_bot")
if not keys[pygame.K_a] and not keys[pygame.K_s] and not keys[pygame.K_d] and not keys[pygame.K_w]:
player_action, player_frame = change_action(player_action, player_frame, "idle")
draw_window(WIN)
解决方案 1:
计算从敌人位置到玩家位置的矢量:
dx = player_x - enemy_x
dy = player_y - enemy_y
计算向量的长度(欧几里得距离):
dist = math.sqrt(dx*dx + dy*dy)
或者
dist = math.hypot(dx, dy)
对向量进行归一化(单位向量)。归一化向量的长度为 1:
if dist > 0:
dx /= dist
dy /= dist
将敌人沿矢量方向移动一定距离。确保移动距离不大于敌人与玩家的剩余距离:
move_dist = min(enemy_vel, dist)
enemy_x += move_dist * dx
enemy_y += move_dist * dy
有关更复杂的解决方案,请参见如何在 pygame 中实现流畅移动
另请参阅跟随目标或鼠标
最小示例:
import pygame, math
pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
player_x, player_y, player_vel = 100, 100, 5
enemy_x, enemy_y, enemy_vel = 300, 300, 3
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
player_x = max(10, min(390, player_x + player_vel * (keys[pygame.K_d] - keys[pygame.K_a])))
player_y = max(10, min(390, player_y + player_vel * (keys[pygame.K_s] - keys[pygame.K_w])))
dx = player_x - enemy_x
dy = player_y - enemy_y
dist = math.hypot(dx, dy)
if dist > 0:
enemy_x += min(enemy_vel, dist) * dx / dist
enemy_y += min(enemy_vel, dist) * dy / dist
window.fill(0)
pygame.draw.circle(window, (0, 128, 255), (player_x, player_y), 10)
pygame.draw.circle(window, (255, 32, 32), (enemy_x, enemy_y), 10)
pygame.display.flip()
pygame.quit()
exit()
对于您的特定代码,该calculate_enemy_movement
函数可能如下所示:
def calculate_enemy_movement(enemy_blob):
dx = player.player_rect.x - enemy_blob.x
dy = player.player_rect.y - enemy_blob.y
dist = math.hypot(dx, dy)
if dist > 0:
move_x = min(enemy_blob.speed, dist) * dx / dist
move_y = min(enemy_blob.speed, dist) * dy / dist
return move_x, move_y
return 0, 0
move_x, move_y = calculate_enemy_movement(enemy_blob)
enemy_blob.x += move_x
enemy_blob.y += move_y
相关推荐
热门文章
项目管理软件有哪些?
热门标签
曾咪二维码
扫码咨询,免费领取项目管理大礼包!
云禅道AD