Как выбрать ближайший объект с учетом размера

#python #pygame

#python #pygame

Вопрос:

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

У меня это пока:

 # both seen and viewer are two different groups
def sight(seen, viewer)
    for entity in viewer:
# This is needed later to decide which way to go, not used here
        currentDir = entity.Direction
# Figure out where the viewer is
        pos = pygame.math.Vector2(entity.rect.centerx, entity.rect.centery)
# Find out who is closest. 
# Uses viewer location and location of each agent in the other group to see who is closest. 
# At the end, divided by size*size of the agent in the other group (for height / width).
# Otherwise they'd pay attention to a tiny agent that's close by 
# instead of a huge agent that's just a bit further away.
        closeby = min([e for e in seen.sprites()], key=lambda e: (pos.distance_to(pygame.math.Vector2(e.rect.centerx, e.rect.centery)) / (e.size * e.size)))
        vector = pygame.math.Vector2((entity.rect.centerx - closeby.rect.centerx), (entity.rect.centery - closeby.rect.centery))
# Get the distance to that other agent
        distance = math.hypot(entity.rect.centerx - closeby.rect.centerx, entity.rect.centery - closeby.rect.centery)
# They can't see forever, so they have a sight limit
            if distance < entity.sight:
                Blah blah, rest of the code here
  

Вот проблема: «если distance <entity.sight» появляется ПОСЛЕ того, как они выбирают «closeby», означает, что они могут «выбрать» крупного агента в качестве ближайшего, который затем устраняется, потому что они слишком далеко.

Представьте это: я агент X. Есть кто-то маленький, о ком я должен беспокоиться (агент Y), который находится в пределах моего визуального диапазона. Однако есть кто-то (агент Z), который действительно большой, который находится за пределами моего визуального диапазона. Агент Z настолько велик, что я выбираю его в качестве «ближайшего». Тогда он находится за пределами визуального диапазона, поэтому никто не выбирается «if distance <entity.sight». Теперь никто не выбран, даже если агент Y находится достаточно близко, он должен был быть выбран.

Я чувствую, что либо поиск

 closeby = min([e for e in etc etc etc
  

должно быть ограничено тем, кто находится в пределах визуального диапазона (но я не знаю, как это сделать), или что, если агент, выбранный как «closeby», находится за пределами визуального диапазона, следует выбрать ВТОРОЙ ближайший. Если они снова находятся вне визуального диапазона, следует выбрать ТРЕТИЙ ближайший и т.д., пока он не попадет в визуальный диапазон. Но я тоже не уверен, как это сделать.

Любая помощь, которую кто-либо может предложить в ограничении «min ([e для e в бла-бла-бла» или для выбора следующего min в этой группе, если первый не означает критерии «entity.sight», была бы чрезвычайно признательна. Я чувствую, что второй вариант (итерация по группе), скорее всего, будет возможен, но я довольно новичок в python, поэтому я не знаю.

Большое вам всем спасибо!

Ответ №1:

Либо используйте цикл, чтобы найти ближайший, а также видимый элемент:

 import math
  
 def sight(seen, viewer)
    for entity in viewer:
        currentDir = entity.Direction
        entityPos = pygame.math.Vector2(entity.rect.center)
    
        minE = None
        minCloseByDist = math.inf
        for e for e in seen.sprites():
            ePos = pygame.math.Vector2(e.rect.center)
            distance = entityPos.distance_to(ePos)
            if distance < entity.sight:
                closeByDist = distance / (e.size * e.size)
                if minE == None or closeByDist < minCloseByDist:
                    minE = e
                    minCloseByDist = minE

        if minE != None:
            # [...]
  

Или вы можете сначала найти все элементы в поле зрения, а затем ближайший элемент:

 def sight(seen, viewer)
    for entity in viewer:
        currentDir = entity.Direction
        entityPos = pygame.math.Vector2(entity.rect.center)
    
        inSight = [e for e in seen.sprites() if entityPos.distance_to(pygame.math.Vector2(e.rect.center)) < entity.sight]
        if inSight:
            closeby = min([e for e in inSight], key=lambda e: (pos.distance_to(pygame.math.Vector2(e.rect.center)) / (e.size * e.size)))

            # [...]