【问题标题】:How to make an object move by itself in order to avoid collisions with other objects如何让一个物体自己移动以避免与其他物体发生碰撞
【发布时间】:2019-11-16 14:02:26
【问题描述】:

我正在制作这款游戏​​,以躲避来自不同方向的物体。我想要实现的是让这个对象(由计算机控制的“玩家”类)能够像用户控制的玩家一样躲闪。

我尝试使用 pygame 提供的基本碰撞处理(当然,请阅读一些文档,了解它的工作原理以及我可以做些什么来解决问题)。我所做的基本上是检查对象的右矩形位置是否与“玩家”的左矩形重叠,反之亦然,因此它会向相反的方向移动以避免碰撞。

TITLE = "Dodging-IA Attempt";
WIDTH = 320; HEIGHT = 400;
FPS = 60;

BLACK = (0,0,0); WHITE = (255,255,255);
RED = (255,0,0); GREEN = (0,255,0); BLUE = (0,0,255);

import pygame as pg;
import random, math;

class Game():
    def __init__(self):
        self.screen = pg.display.set_mode((WIDTH,HEIGHT));
        self.clock = pg.time.Clock(); self.dt = FPS/1000;
        self.running = True;
        self.all_sprites = pg.sprite.Group();
        self.bullets = pg.sprite.Group();
        self.other_sprites = pg.sprite.Group();

        self.player = Player(); self.all_sprites.add(self.player);
        self.bullet_spawn = BulletSpawn(); self.other_sprites.add(self.bullet_spawn);


class Player(pg.sprite.Sprite):
    def __init__(self):
        pg.sprite.Sprite.__init__(self);
        self.image = pg.Surface((16,32)); self.image.fill(GREEN);
        self.rect = self.image.get_rect();
        self.rect.centerx = WIDTH//2;
        self.rect.y = HEIGHT*3//4;
        self.vx = self.vy = 300;

    def update(self,dt):
        pass;

class Bullet(pg.sprite.Sprite):
    def __init__(self,x):
        pg.sprite.Sprite.__init__(self);
        self.image = pg.Surface((16,16)); self.image.fill(RED);
        self.rect = self.image.get_rect();
        self.rect.centerx = x;
        self.rect.bottom = 0;
        self.vy = 70;

    def update(self,dt):
        self.rect.y += self.vy * dt;
        if self.rect.top > HEIGHT:
            self.kill();

class BulletSpawn(pg.sprite.Sprite):
    def __init__(self):
        pg.sprite.Sprite.__init__(self);
        self.image = pg.Surface((1,1)); self.rect = self.image.get_rect();
        self.new_bullet = pg.time.get_ticks();

    def update(self):
        now = pg.time.get_ticks();
        if now - self.new_bullet > 500:
            self.new_bullet = now;
            for i in range(5):
                bullet = Bullet(random.randint(8,WIDTH-8));
                game.bullets.add(bullet);
                game.all_sprites.add(bullet);

pg.init();
pg.display.set_caption(TITLE);

game = Game();

while game.running:

    game.dt = game.clock.tick(FPS)/1000;

    for event in pg.event.get():
        if event.type == pg.QUIT:
            game.running = False;

    hits = pg.sprite.spritecollide(game.player,game.bullets,False)
    for hit in hits:
        if hit.rect.right > game.player.rect.left:  #dodge moving to left
            game.player.rect.x += game.player.vx*game.dt
            print("DODGED TO LEFT")
        if hit.rect.left < game.player.rect.right:  #dodge moving to right
            game.player.rect.x -= game.player.vx*game.dt
            print("DODGED TO RIGHT")


    game.all_sprites.update(game.dt);
    game.other_sprites.update();

    game.screen.fill(BLUE);
    game.all_sprites.draw(game.screen)
    game.other_sprites.draw(game.screen)
    pg.display.flip();

pg.quit();

因此,“玩家”无论是否在其路径上发生碰撞,都始终向一个且仅一个方向移动,而不是实际水平躲避坠落的物体。我该怎么做才能得到这个?也许我必须重新制定碰撞的条件? 非常感谢您的宝贵时间。

【问题讨论】:

    标签: python-3.x pygame python-3.6


    【解决方案1】:

    无论碰撞时玩家和子弹的矩形位置如何,bullet.rect.right 总是大于player.rect.leftbullet.rect.left 总是小于player.rect.right。如果在纸上画,您可以直观地看到它。在这里更好地检查移动侧推矩形中心。 这段代码:

            if hit.rect.right > game.player.rect.left:  #dodge moving to left
                game.player.rect.x += game.player.vx*game.dt
                print("DODGED TO LEFT")
            if hit.rect.left < game.player.rect.right:  #dodge moving to right
                game.player.rect.x -= game.player.vx*game.dt
                print("DODGED TO RIGHT")
    

    你可以改变它:

            if hit.rect.center > game.player.rect.center:
                game.player.rect.x -= game.player.vx*game.dt
            elif hit.rect.center < game.player.rect.center:
                game.player.rect.x += game.player.vx*game.dt
    

    您可能会针对抽搐的传递进行一些优化,但我认为错误的性质很明显。

    【讨论】:

    • 哦,我明白了,这确实有效!虽然......它总是朝着同一个方向前进(左边,也许它与条件的顺序有关,或者我猜......)并且即使有更多的空间可以躲避这个方向,它也会试图躲避正确的。但它成功了,所以还是谢谢你!
    【解决方案2】:

    检查盒子边缘是否在播放器范围内是一种方法。如果您使检查包含在内,即使只有边缘对齐,玩家也应该躲避。

    if hit.rect.right >= game.player.rect.left and hit.rect.left <= game.player.rect.left:
        game.player.rect.x += game.player.vx*game.dt
        print("DODGED TO LEFT")
    elif hit.rect.left <= game.player.rect.right and hit.rect.right >= game.player.rect.right:
        game.player.rect.x -= game.player.vx*game.dt
        print("DODGED TO RIGHT")
    

    【讨论】:

    • 非常感谢!我已经尝试过你的代码,它产生了奇迹......我有点明白那里发生了什么,并且有点因为没有考虑它而感到愚蠢......谢谢,它按预期移动并且对象“明智地”选择躲避的地方.非常感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-11
    • 2011-04-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多