1
votes

I'm making this game about dodging objects that come from different directions. What I'm trying to achieve is to get this object (a 'player' class controlled by the computer) to be able to dodge just like a player controlled by user would do.

I've tried to use basic collisions handling provided by pygame (of course, read some documentation about how it works and what could I do to solve the problem). What I did was basically check if an object's right rect position overlaps the 'player's' left rect and viceversa, so it moves to the opposite direction to avoid the collision.

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();

As a result, the 'player' moves always to one and only one direction no matter if it collides or not in its path instead of actually dodging horizontally the falling objects. What could I do to get this? Maybe I have to reformulate the collision's conditions? Thank you so much for your time.

2

2 Answers

1
votes

Checking that the boxes edge is within the player span is a way to do this. If you make the check inclusive, the player should dodge even if only the edged are aligned.

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")
2
votes

Regardless of player and bullet rect positions in colliding moment, bullet.rect.right always be more than player.rect.left and bullet.rect.left always be less than player.rect.right. You visually see it if draw on paper. Here better check moving side pushing rects centers. This piece of code:

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

You may change on it:

        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

You may do some optimisations for deliverance of twitching, but i think nature of mistake is clearly.