Есть ли способ плавно перемещать объект в пигме в случайных направлениях? - PullRequest
1 голос
/ 25 апреля 2020

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

Мой код (большинство не имеет значения):

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

Ответы [ 3 ]

0 голосов
/ 25 апреля 2020

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

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

Лично я бы, вероятно, go с последним, но это потребовало бы немного тригонометрии, тогда как целевую версию можно было бы просто сделать с помощью rat ios и теоремы Пифагора.

0 голосов
/ 25 апреля 2020

Используйте pygame.math.Vector2 для выполнения вычислений. Сохраните координаты большого двоичного объекта в Vector2 и определите максимальное расстояние (self.maxdist), скорость (self.speed), случайное расстояние (self.dist) и случайное направление (self.dir). Случайное направление - это вектор длиной 1 ( Единичный вектор ) и случайный ангел (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))

Когда шарик движется, тогда масштабируйте направление по скорости и добавьте его в положение (self.pos += self.dir * self.speed). Уменьшите расстояние (self.dist -= self.speed) и обновите self.x, self.y на округленную (round) позицию. Если self.dist падает ниже 0, создайте новое случайное направление и расстояние:

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

В методе limit вы должны убедиться, что self.pos находится в границах. Наконец, вам нужно обновить 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)

Класс FastBlob не нуждается в своем собственном методе move. Достаточно определить его собственные self.maxdist и 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
0 голосов
/ 25 апреля 2020

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

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

И вот как я установил его в главном l oop:

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

Надеюсь, вы найдете это полезным.

...