Как заставить объект двигаться самостоятельно, чтобы избежать столкновения с другими объектами - PullRequest
1 голос
/ 06 июля 2019

Я делаю эту игру об уклонении от объектов, которые приходят с разных направлений. Я пытаюсь добиться того, чтобы этот объект (класс «игрока», управляемый компьютером) мог увернуться, точно так же, как это сделал бы игрок, управляемый пользователем.

Я пытался использовать базовую обработку коллизий, предоставляемую 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();

В результате «игрок» всегда движется в одном и только одном направлении, независимо от того, сталкивается он или нет на своем пути, вместо того, чтобы фактически уклоняться от падающих объектов по горизонтали. Что я мог сделать, чтобы получить это? Может быть, мне нужно переформулировать условия столкновения? Большое спасибо за ваше время.

Ответы [ 2 ]

2 голосов
/ 06 июля 2019

Независимо от положения прямоугольника игрока и пули в момент столкновения, bullet.rect.right всегда будет больше player.rect.left, а bullet.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

Вы можете сделать некоторые оптимизации для избавления от подергивания, но я думаю, что природа ошибки очевидна.

1 голос
/ 07 июля 2019

Проверка того, что край бокса находится в пределах игрового диапазона, - это способ сделать это. Если вы делаете проверку включительно, игрок должен увернуться, даже если выровнены только края.

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")
...