pygame敌人向玩家的2维运动,如何计算x和y速度?

杰伊·恩格尔

在当前正在制作的游戏中,我需要向玩家(这里是敌人)发出一个敌人的移动才能做到这一点,我已经创建了一个函数:def calculate_enemy_movement(enemy):并且在其中放入了该函数需要执行的操作:

计算什么X值需要被添加的每一帧(X速度),以及什么Y值需要被添加的每一帧(Y速度)向enemy.xenemy.y朝行走player.xplayer.y,然后返回X速度和返回ÿ速度。
在此调用此函数:每帧将x速度和y速度添加到敌人的x和y posenemy_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)
拉比德76

计算从敌人位置到玩家位置的向量:

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

pygame敌人向玩家的2维运动,如何计算x和y速度?

来自分类Dev

Pygame 简单运动:敌人模仿玩家运动并回溯步骤

来自分类Dev

如何使玩家的直肠在我的敌人的侧面和底部碰撞?Pygame

来自分类Dev

在pygame中计算X和Y速度以击中2d平面上的目标

来自分类Dev

如何让敌人跟随pygame中的玩家?

来自分类Dev

如何让敌人跟随 Pygame 中的玩家?

来自分类Dev

我如何让敌人向玩家移动并预测其在pygame中的路径

来自分类Dev

Pygame Platformer 2D中的敌人运动

来自分类Dev

Pygame-如何正确计算玩家点数?

来自分类Dev

我如何让角色加速和减速而不是仅以一定速度运动(在pygame中)?

来自分类Dev

Pygame吃豆子-敌人随机运动

来自分类Dev

靠近时如何使敌人转身向玩家移动?Unity3D

来自分类Dev

当玩家与敌人发生碰撞时如何阻止敌人旋转

来自分类Dev

给定开始点,结束点,速度和运动开始时间后,在二维中计算对象当前坐标的方法是否更丑陋?

来自分类Dev

如何将敌人移向移动的玩家?

来自分类Dev

如何阻止敌人立即杀死玩家?

来自分类Dev

unity 获取运动的 X 和 Y

来自分类Dev

计算玩家射击pygame的方向

来自分类Dev

如何获得ndarray的x和y维-Numpy / Python

来自分类Dev

如何增加难度?(例如,增加敌人的速度,增加敌人的数量)

来自分类Dev

pygame输入和运动平滑

来自分类Dev

pygame和精灵模糊运动

来自分类Dev

您如何计算一系列的tictactoe(x和o)重赛中玩家的赢,输和平局?

来自分类Dev

将位图从(x,y)移至(x2,y2)如何计算起始和目标之间的x,y值

来自分类Dev

时间和敌人出现的问题(Python,Pygame)

来自分类Dev

敌人不会跟随玩家。SDL2 / C ++

来自分类Dev

OpenGL-2D敌人无法旋转到面对玩家

来自分类Dev

玩家总是与敌人接触

来自分类Dev

玩家总是与敌人接触

Related 相关文章

  1. 1

    pygame敌人向玩家的2维运动,如何计算x和y速度?

  2. 2

    Pygame 简单运动:敌人模仿玩家运动并回溯步骤

  3. 3

    如何使玩家的直肠在我的敌人的侧面和底部碰撞?Pygame

  4. 4

    在pygame中计算X和Y速度以击中2d平面上的目标

  5. 5

    如何让敌人跟随pygame中的玩家?

  6. 6

    如何让敌人跟随 Pygame 中的玩家?

  7. 7

    我如何让敌人向玩家移动并预测其在pygame中的路径

  8. 8

    Pygame Platformer 2D中的敌人运动

  9. 9

    Pygame-如何正确计算玩家点数?

  10. 10

    我如何让角色加速和减速而不是仅以一定速度运动(在pygame中)?

  11. 11

    Pygame吃豆子-敌人随机运动

  12. 12

    靠近时如何使敌人转身向玩家移动?Unity3D

  13. 13

    当玩家与敌人发生碰撞时如何阻止敌人旋转

  14. 14

    给定开始点,结束点,速度和运动开始时间后,在二维中计算对象当前坐标的方法是否更丑陋?

  15. 15

    如何将敌人移向移动的玩家?

  16. 16

    如何阻止敌人立即杀死玩家?

  17. 17

    unity 获取运动的 X 和 Y

  18. 18

    计算玩家射击pygame的方向

  19. 19

    如何获得ndarray的x和y维-Numpy / Python

  20. 20

    如何增加难度?(例如,增加敌人的速度,增加敌人的数量)

  21. 21

    pygame输入和运动平滑

  22. 22

    pygame和精灵模糊运动

  23. 23

    您如何计算一系列的tictactoe(x和o)重赛中玩家的赢,输和平局?

  24. 24

    将位图从(x,y)移至(x2,y2)如何计算起始和目标之间的x,y值

  25. 25

    时间和敌人出现的问题(Python,Pygame)

  26. 26

    敌人不会跟随玩家。SDL2 / C ++

  27. 27

    OpenGL-2D敌人无法旋转到面对玩家

  28. 28

    玩家总是与敌人接触

  29. 29

    玩家总是与敌人接触

热门标签

归档