1

I'm trying to make blobs move in a random direction for several frames rather than just once so that it appears less jerky and more smooth, but have been unable to do so. Is there any way to make each object move in the same direction for several ticks before choosing another random direction and doing the same?

My code (most is irrelevant):

import pygame
import random
import numpy as np

WIDTH = 1800
HEIGHT = 1000
BLUE = (15,15,180)
RED = (150,0,0)

class Blob:
    def __init__(self, colour, x_boundary, y_boundary, size):
        self.colour = colour
        self.size = size
        self.x_boundary = x_boundary
        self.y_boundary = y_boundary
        self.x = random.randrange(0, self.x_boundary)
        self.y = random.randrange(0, self.y_boundary)

    def move(self):
        self.x += random.randrange(-6,7)
        self.y += random.randrange(-6,7)

    def limits(self):
        if self.x < 0:
            self.x = 0
        elif self.x > self.x_boundary:
            self.x = self.x_boundary
        if self.y < 0:
            self.y = 0
        elif self.y > self.y_boundary:
            self.y = self.y_boundary

    def __add__(self, other_blob):
        if other_blob.size > self.size:
                other_blob.size += int(self.size * 0.5)
                self.size = 0

class FastBlob(Blob):
    def __init__(self, colour, x_boundary, y_boundary, size):
        super().__init__(colour, x_boundary, y_boundary, size)
    def move(self):
        self.x += random.randrange(-20,21)
        self.y += random.randrange(-20,21)

pygame.init()
game_display = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Blob world')
clock = pygame.time.Clock()

def is_touching(b1,b2):
    return np.linalg.norm(np.array([b1.x,b1.y])-np.array([b2.x,b2.y])) < (b1.size + b2.size)

def handle_collisions(blob_list):
    blues, reds, slow_reds = blob_list
    for first_blobs in blues, reds, slow_reds:
        for first_blob_id, first_blob in first_blobs.copy().items():
            for other_blobs in blues, reds, slow_reds:
                for other_blob_id, other_blob in other_blobs.copy().items():
                    if first_blob == other_blob:
                        pass
                    else:
                        if is_touching(first_blob, other_blob):
                            first_blob + other_blob
    return blues, reds, slow_reds

def draw_environment(blob_list):
    game_display.fill((210,210,210))
    handle_collisions(blob_list)
    for blob_dict in blob_list:
        for blob_id in blob_dict:
            blob = blob_dict[blob_id]
            pygame.draw.circle(game_display, blob.colour, [blob.x, blob.y], blob.size)
            blob.move()
            blob.limits()
    pygame.display.update()

def main():
    blue_blobs = dict(enumerate([FastBlob(BLUE, WIDTH, HEIGHT, random.randrange(10,15)) for i in range(20)]))
    red_blobs = dict(enumerate([FastBlob(RED, WIDTH, HEIGHT, random.randrange(5,10)) for i in range(30)]))
    slow_red_blobs = dict(enumerate([Blob(RED, WIDTH, HEIGHT, random.randrange(20,30)) for i in range(5)]))
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit()
        draw_environment([blue_blobs, red_blobs, slow_red_blobs])
        clock.tick(7)

if __name__ == '__main__':
    main()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
John Smith
  • 11
  • 2
  • You could have a variable such as `move_randomly = False` and then after a few loops, set it to true, move the object, then set it to false for a few more loops. – Holden Apr 24 '20 at 22:24
  • You could also take a look at perlin noise. – 63677 Apr 24 '20 at 22:34

2 Answers2

0

Here, I have similar problem in my game, when enemy has to randomly change directions so it is unpredictable to the player.

def goblin_move():                                                  #Goblin auto (random) movement

    if goblin.x < 0:
        goblin.go_right()
    elif goblin.x > 500:
        goblin.go_left()
    else:
        if goblin.x > (rnd_1 * win_width) and goblin.move_flag == -1:
            goblin.go_left()
            goblin.move_flag = -1

        else:
            goblin.go_right()
            goblin.move_flag = 1

    if goblin.x > (rnd_2 * win_width):
        goblin.move_flag = -1


def set_random(rnd_1, rnd_2):                                       #Random function generator

    rnd_1 = round(random.uniform(0, 0.45), 2)
    rnd_2 = round(random.uniform(0.65, 0.95), 2)

    return rnd_1, rnd_2

And this is how I set it in the main loop:

if round(pg.time.get_ticks()/1000) % 3 == 0:        #Calling random function
        (rnd_1, rnd_2) = set_random(rnd_1, rnd_2)

Hope you will find it useful.

kaktus_car
  • 986
  • 2
  • 11
  • 19
0

Use pygame.math.Vector2 to do the computations. Store the coordinates of the blob to a Vector2 and define a maximum distance (self.maxdist), a velocity (self.speed), a random distance (self.dist) a nd a random direction (self.dir). The random direction is a vector with length 1 (Unit vector) and a random angel (rotate()):

class Blob:
    def __init__(self, colour, x_boundary, y_boundary, size):
        self.colour = colour
        self.size = size
        self.x_boundary = x_boundary
        self.y_boundary = y_boundary
        self.x = random.randrange(0, self.x_boundary)
        self.y = random.randrange(0, self.y_boundary)
        self.pos = pygame.math.Vector2(self.x, self.y)
        self.maxdist = 7
        self.speed = 1
        self.dist = random.randrange(self.maxdist)
        self.dir = pygame.math.Vector2(1, 0).rotate(random.randrange(360))

When the blob moves, then scale the direction by the speed and add it to the position (self.pos += self.dir * self.speed). Decrement the distance (self.dist -= self.speed) and update self.x, self.y by the rounded (round) position. If self.dist falls below 0, the create a new random direction and distance:

class Blob:
    # [...]

    def move(self):
        self.pos += self.dir * self.speed
        self.dist -= self.speed
        self.x, self.y = round(self.pos.x), round(self.pos.y)

        if self.dist <= 0:
            self.dist = random.randrange(self.maxdist)
            self.dir = pygame.math.Vector2(1, 0).rotate(random.randrange(360))

In the method limit you have to ensure that self.pos is in bounds. Finally you have to update self.x, self.y:

class Blob:
    # [...]

    def limits(self):
        if self.pos.x < 0:
            self.pos.x = 0
        elif self.pos.x > self.x_boundary:
            self.pos.x = self.x_boundary
        if self.pos.y < 0:
            self.pos.y = 0
        elif self.pos.y > self.y_boundary:
            self.pos.y = self.y_boundary
        self.x, self.y = round(self.pos.x), round(self.pos.y)

The class FastBlob does not need its own move method. It is sufficient do define its own self.maxdist and self.speed:

class FastBlob(Blob):
    def __init__(self, colour, x_boundary, y_boundary, size):
        super().__init__(colour, x_boundary, y_boundary, size)
        self.maxdist = 35
        self.speed = 5
Rabbid76
  • 202,892
  • 27
  • 131
  • 174