为了账号安全,请及时绑定邮箱和手机立即绑定

我怎样才能让敌人向玩家移动并在pygame中预测它的路径

我怎样才能让敌人向玩家移动并在pygame中预测它的路径

翻翻过去那场雪 2022-12-20 16:40:47
我正在制作一个 pygame 游戏,我希望我的敌人跟随玩家并预测它的路径。我不只是想缩短玩家和敌人之间的距离。敌人的数量会根据等级而定,每升3级就会增加一个新的敌人。我附上了我的整个代码和一张截图,显示我的敌人目前正在直线移动。
查看完整描述

1 回答

?
泛舟湖上清波郎朗

TA贡献1818条经验 获得超3个赞

为此你需要一些矢量数学,所以我建议重构你的代码并学习如何使用Sprites你可以在这里找到一个例子。

要找到问题的答案(“预测路径”),您可以在 google 上搜索intercept vectoror pursuit vector。那应该会产生一些结果,例如如何计算截距的向量?计算拦截矢量

例如,我翻译了第二个问题的最后一个答案并将其复制/粘贴到我的一个答案中,因为 a) 我懒得再写一遍 b) 有一个代码点我必须更改才能实现拦截逻辑(EnemyController类)。

import pygame

import random

import math

from pygame import Vector2


SPRITE_SHEET = None


GREEN_SHIP  = pygame.Rect(0, 292, 32, 32)

RED_SHIP    = pygame.Rect(0, 324, 32, 32)

BLUE_SHIP   = pygame.Rect(0, 356, 32, 32)

YELLOW_SHIP = pygame.Rect(0, 388, 32, 32)



class EnemyController:


    def __init__(self, target):

        self.direction = Vector2(1, 0)

        self.target = target


    def update(self, sprite, events, dt):

        k = self.target.vel.magnitude() / sprite.speed;


        distance_to_target = (sprite.pos - self.target.pos).magnitude()


        b_hat = self.target.vel

        c_hat = sprite.pos - self.target.pos


        CAB = b_hat.angle_to(c_hat)

        ABC = math.asin(math.sin(CAB) * k)

        ACB = math.pi - (CAB + ABC)


        j = distance_to_target / math.sin(ACB)

        a = j * math.sin(CAB)

        b = j * math.sin(ABC)


        time_to_collision = b / self.target.vel.magnitude() if self.target.vel.magnitude() > 0 else 1

        collision_pos = self.target.pos + (self.target.vel * time_to_collision)


        v = sprite.pos - collision_pos

        if v.length() > 0:

            sprite.direction = -v.normalize()


        if v.length() <= 10:

            sprite.pos = pygame.Vector2(400, 100)


class PlayerController:


    movement = {

        pygame.K_UP:    Vector2( 0, -1),

        pygame.K_DOWN:  Vector2( 0,  1),

        pygame.K_LEFT:  Vector2(-1,  0),

        pygame.K_RIGHT: Vector2( 1,  0)

    }


    def update(self, sprite, events, dt):

        pressed = pygame.key.get_pressed()

        v = Vector2(0, 0)

        for key in PlayerController.movement:

            if pressed[key]:

                v += PlayerController.movement[key]


        sprite.direction = v


        for e in events:

            if e.type == pygame.KEYDOWN:

                if e.key == pygame.K_SPACE:

                    sprite.groups()[0].add(Explosion(sprite.pos))


class Animation:

    def __init__(self, frames, speed, sprite):

        self.sprite = sprite

        self.speed = speed

        self.ticks = 0

        self.frames = frames

        self.running = 0

        self.start()


    def cycle_func(self, iterable):

        saved = []

        for element in iterable:

            yield element

            saved.append(element)

        if hasattr(self.sprite, 'on_animation_end'):

            self.sprite.on_animation_end()

        while saved:

            for element in saved:

                yield element

            if hasattr(self.sprite, 'on_animation_end'):

                self.sprite.on_animation_end()

    def stop(self):

        self.running = 0

        if self.idle_image:

            self.sprite.image = self.idle_image


    def start(self):

        if not self.running:

            self.running = 1

            self.cycle = self.cycle_func(self.frames)

            self.sprite.image = next(self.cycle)


    def update(self, dt):

        self.ticks += dt

        if self.ticks >= self.speed:

            self.ticks = self.ticks % self.speed

            if self.running:

                self.sprite.image = next(self.cycle)


class AnimatedSprite(pygame.sprite.Sprite):


    def __init__(self, pos, frames, speed):

        super().__init__()

        self.animation = Animation(frames, speed, self)

        self.rect = self.image.get_rect(center=pos)

        self.pos = Vector2(pos)

        self.animation.start()


    def update(self, events, dt):

        self.animation.update(dt)


class Explosion(AnimatedSprite):


    frames = None


    def __init__(self, pos):

        if not Explosion.frames:

            Explosion.frames = parse_sprite_sheet(SPRITE_SHEET, pygame.Rect(0, 890, 64, 64), 6, 4)


        super().__init__(pos, Explosion.frames, 50)


    def on_animation_end(self):

        self.kill()


class DirectionalImageSprite(pygame.sprite.Sprite):


    directions = [(1,0),(1,-1),(0,-1),(-1,-1),(-1,0),(-1,1),(0,1),(1,1),(0,0)]


    def __init__(self, pos, directional_images_rect):

        super().__init__()

        images = parse_sprite_sheet(SPRITE_SHEET, directional_images_rect, 9, 1)

        self.images = { x: img for (x, img) in zip(DirectionalImageSprite.directions, images) }

        self.direction = Vector2(0, 0)

        self.image = self.images[(self.direction.x, self.direction.y)]

        self.rect = self.image.get_rect(center=pos)

        self.pos = pygame.Vector2(pos)


class SpaceShip(DirectionalImageSprite):


    def __init__(self, pos, controller, directional_images_rect):

        super().__init__(pos, directional_images_rect)

        self.controller = controller

        self.speed = 2

        self.vel = pygame.Vector2(0, 0)


    def update(self, events, dt):

        super().update(events, dt)


        if self.controller:

            self.controller.update(self, events, dt)


        self.vel = Vector2(0, 0)

        if (self.direction.x, self.direction.y) in self.images:

            self.image = self.images[(self.direction.x, self.direction.y)]

        if self.direction.length():

            self.vel = self.direction.normalize() * self.speed

            self.pos += self.vel


        self.rect.center = int(self.pos[0]), int(self.pos[1])


def parse_sprite_sheet(sheet, start_rect, frames_in_row, lines):

    frames = []

    rect = start_rect.copy()

    for _ in range(lines):

        for _ in range(frames_in_row):

            frame = sheet.subsurface(rect)

            frames.append(frame)

            rect.move_ip(rect.width, 0)

        rect.move_ip(0, rect.height)

        rect.x = start_rect.x

    return frames


def main():

    screen = pygame.display.set_mode((800, 600))

    global SPRITE_SHEET

    SPRITE_SHEET = pygame.image.load("ipLRR.png").convert_alpha()

    clock = pygame.time.Clock()

    dt = 0

    player = SpaceShip((400, 300), PlayerController(), YELLOW_SHIP)

    enemy = SpaceShip((400, 100), EnemyController(player), GREEN_SHIP)

    enemy.speed = 4

    all_sprites = pygame.sprite.Group(

        player,

        enemy

    )


    while True:

        events = pygame.event.get()


        for e in events:

            if e.type == pygame.QUIT:

                return


        all_sprites.update(events, dt)


        screen.fill((0, 0, 0))

        all_sprites.draw(screen)

        pygame.display.flip()

        dt = clock.tick(120)


main()


https://i.stack.imgur.com/lapWw.gif


查看完整回答
反对 回复 2022-12-20
  • 1 回答
  • 0 关注
  • 96 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信