Je travaille sur des jeux 2D avec Pygame. J'ai besoin de placer plusieurs objets en même temps de manière aléatoire Méthodes évidentes suivez (en pseudo): p> Cette méthode a pris pour toujours. p> Autre méthode J'ai essayé: p> Cette méthode est renvoyée près des listes vides. P> Je traite avec une liste qui est n'importe où de 2 - 20 objets grands. Toute suggestion? P>
7 Réponses :
list_of_objects = [] for i in range(20): while True: new_object = create_object() if not any(collides(new_object, x) for x in list_of_objects): break list_of_objects.append(new_object) I assume you already have the create_object() and collides() functionsYou may also need to decrease the size of the rects if this loops too many times
Je ne sais pas pourquoi, mais votre méthode, comme la mienne, des rect à chevauchement générés inexplicablement ... il regarde i> comme ça devrait fonctionner ... Je ne sais pas ce qui s'est mal passé.
@John, peut-être que leur est un bogue dans votre fonction de collision. Pouvez-vous poster le code pour cela?
J'utilise les objets de pygames records intégrés dans la fonction CollidAderect (autre_rect). Malheureusement, je ne trouve pas le code pour cela, mais je vais essayer d'utiliser une fonction différente et de vous contacter.
J'ai trouvé l'autre fonction de collision et j'ai essayé aussi. Cela n'a pas fonctionné non plus. Le code est ici: Pastebin.com/a8qvc89g
Trois idées:
La première méthode échoue car frapper une matrice aléatoire de 20 objets non chevauchants est très improbable (en réalité est la probabilité de deux objets en collision). Si vous pouviez radicalement (les commandes de magnitude du drame) diminuer leur taille, cela pourrait aider. P> L'amélioration la plus évidente serait: P> (1-p) ^ 20 code>, où
0
Choisissez-les un par un h3>
while len(rectangles)<N:
new_rectangle=get_random_rectangle()
for rectangle in rectangles:
if not any(intersects (rectangle, new_rectangle) for rectangle in rectangles)
rectangles.add(new_rectangle)
Vous pouvez utiliser une instruction continuer code> ou - si vous vous sentez assez aventureux - une application minutieuse du
n'importe quel code> intégré, pour simplifier la logique ici.
Je ne m'attendais pas à ce que vous utilisiez b>! ;) Nous pouvons simplement faire si non (...): # Faites l'ajout code>. De plus, vous n'avez pas besoin des crochets ici: Lisez sur les compréhensions des générateurs.
tout code> accepte les ittérables, pas seulement des séquences. En outre, cela est cassé maintenant car le
pour code> la boucle répète la logique implémentée avec
tout code>. :(
Je ne devrais jamais écrire de code avant 9h00 et deux tasses de café.
Avez-vous essayé:
Until there are enough objects: create new object if it doesn't collide with anything in the list: add it to the list
Vient d'essayer ça. Il a itéré plus de 50 000 fois sans trouver 20 rects. Je suis toujours novice, donc je ne sais pas comment trouver la région d'intersection beaucoup moins le centre de celui-ci! Je suis simplement en utilisant la méthode de Pygames Colliderect () pour dire si i> ils entrent en collision. Malheureusement, je ne peux pas dire où i>.
Comment choisissez-vous des tailles de rectangle?
@Karl: Désolé, je n'ai pas vu ton commentaire. Sans "@john" je n'ai jamais été informé de cela. Les tailles de rectangle sont aléatoires. J'utilise hasard.Randint (début, fin) pour les obtenir.
@John Oui, si vous choisissez des tailles de rectangle comme celle-ci, alors bien sûr, il sera très difficile d'obtenir 20 rectangles non chevauchants ... Pensez à ce que sera la zone moyenne d'un rectangle donné!
@Karl: hmm tu as raison. Pouvez-vous suggérer un meilleur moyen de choisir des tailles de rectangle?
@John je pourrais faire plusieurs suggestions sans y penser trop, mais je pense vraiment que vous seriez mieux servi en essayant de trouver quelque chose vous-même. :) Je pense que certaines des autres réponses / commentaires mentionnés à cela aussi.
@Karl: D'accord, je vais voir ce que je peux faire. Merci pour l'aide.
Un pseudocode alternatif, à ceux déjà mentionnés: ou quelque chose comme ça. p> Mais cela a l'avantage de créer éventuellement de créer des objets plus petits que vous ne vouliez et créer des objets qui se croisent presque (c.-à-d. Touch). P> Si c'est une carte pour le joueur de traverser, ils ne pourront toujours pas le traverser parce que leur chemin pourrait être bloqué. P> p>
J'ai changé ma réponse un peu pour répondre à votre question de suivi sur le point de savoir s'il pourrait être modifié pour générer au lieu de générer des carrés de non-collision aléatoires des carrés em> plutôt que des rectangles arbitrairement. Je l'ai fait de la manière la plus simple que je puisse travailler, qui devait poster la production rectangulaire de ma réponse originale et transformer son contenu en sous-régions carrées. Je également mis à jour le code de visualisation en option pour montrer les deux types de sortie. Évidemment, ce type de filtrage pourrait être étendu pour faire d'autres choses comme l'instar de chaque rectangle ou de la place légèrement pour les empêcher de se toucher. Ma réponse évite de faire ce que bon nombre des réponses déjà publiées - qui génèrent des rectangles tout en générant au hasard. rejeter toutes celles qui entrent en collision avec tout déjà créé - parce que cela semble intrinsèquement lent et informatiquement gaspillage. Mon approche se concentre à la place pour générer uniquement ceux qui ne se chevauchent pas en premier lieu. P> qui doit être fait relativement simple en le transformant en un simple problème de subdivision de surface qui peut être effectué très rapidement. Vous trouverez ci-dessous une implémentation de la manière dont cela peut être fait. Elle commence par un rectangle définissant la limite extérieure qui la divise en quatre petits rectangles ne se chevauchent pas. Cela est accompli en choisissant un point intérieur semi-aléatoire et l'utiliser en même temps que les quatre points d'angle existants du rectangle extérieur pour former les quatre sous-sections. P> La plupart du lieu de prendre d'action dans le Étant donné que cet algorithme génère des sous-rectangles très rapidement, il est correct de passer du temps de calcul déterminant le point de division intérieure. P> Pour visualiser les résultats de cette approche, il y a un code non essentiel à la fin que les utilisations du module Quoi qu'il en soit, voici la dernière version du code et des échantillons de sortie: p> quadsect () code> fonction. Le choix du point intérieur est crucial pour déterminer ce que ressemble à la sortie. Vous pouvez contraindre comme vous le souhaitez, par exemple que la sélection qui se traduirait par des sous-rectangles d'au moins une certaine largeur minimale ou à la hauteur ou pas plus grand que une certaine quantité. Dans le code échantillon dans ma réponse, il est défini comme étant le point central  ± 1 sup> / 3 sub> de la largeur et la hauteur du rectangle extérieur, mais au fond tout point intérieur fonctionnerait Dans une certaine mesure. P>
PIL code> (Python Imaging Library) pour créer un fichier image affichant les rectangles générés au cours de certaines courses d'essai j'ai fait. p>
import random
from random import randint
random.seed()
NUM_RECTS = 20
REGION = Rect(0, 0, 640, 480)
class Point(object):
def __init__(self, x, y):
self.x, self.y = x, y
@staticmethod
def from_point(other):
return Point(other.x, other.y)
class Rect(object):
def __init__(self, x1, y1, x2, y2):
minx, maxx = (x1,x2) if x1 < x2 else (x2,x1)
miny, maxy = (y1,y2) if y1 < y2 else (y2,y1)
self.min, self.max = Point(minx, miny), Point(maxx, maxy)
@staticmethod
def from_points(p1, p2):
return Rect(p1.x, p1.y, p2.x, p2.y)
width = property(lambda self: self.max.x - self.min.x)
height = property(lambda self: self.max.y - self.min.y)
plus_or_minus = lambda v: v * [-1, 1][(randint(0, 100) % 2)] # equal chance +/-1
def quadsect(rect, factor):
""" Subdivide given rectangle into four non-overlapping rectangles.
'factor' is an integer representing the proportion of the width or
height the deviatation from the center of the rectangle allowed.
"""
# pick a point in the interior of given rectangle
w, h = rect.width, rect.height # cache properties
center = Point(rect.min.x + (w // 2), rect.min.y + (h // 2))
delta_x = plus_or_minus(randint(0, w // factor))
delta_y = plus_or_minus(randint(0, h // factor))
interior = Point(center.x + delta_x, center.y + delta_y)
# create rectangles from the interior point and the corners of the outer one
return [Rect(interior.x, interior.y, rect.min.x, rect.min.y),
Rect(interior.x, interior.y, rect.max.x, rect.min.y),
Rect(interior.x, interior.y, rect.max.x, rect.max.y),
Rect(interior.x, interior.y, rect.min.x, rect.max.y)]
def square_subregion(rect):
""" Return a square rectangle centered within the given rectangle """
w, h = rect.width, rect.height # cache properties
if w < h:
offset = (h - w) // 2
return Rect(rect.min.x, rect.min.y+offset,
rect.max.x, rect.min.y+offset+w)
else:
offset = (w - h) // 2
return Rect(rect.min.x+offset, rect.min.y,
rect.min.x+offset+h, rect.max.y)
# call quadsect() until at least the number of rects wanted has been generated
rects = [REGION] # seed output list
while len(rects) <= NUM_RECTS:
rects = [subrect for rect in rects
for subrect in quadsect(rect, 3)]
random.shuffle(rects) # mix them up
sample = random.sample(rects, NUM_RECTS) # select the desired number
print '%d out of the %d rectangles selected' % (NUM_RECTS, len(rects))
#################################################
# extra credit - create an image file showing results
from PIL import Image, ImageDraw
def gray(v): return tuple(int(v*255) for _ in range(3))
BLACK, DARK_GRAY, GRAY = gray(0), gray(.25), gray(.5)
LIGHT_GRAY, WHITE = gray(.75), gray(1)
RED, GREEN, BLUE = (255, 0, 0), (0, 255, 0), (0, 0, 255)
CYAN, MAGENTA, YELLOW = (0, 255, 255), (255, 0, 255), (255, 255, 0)
BACKGR, SQUARE_COLOR, RECT_COLOR = (245, 245, 87), (255, 73, 73), (37, 182, 249)
imgx, imgy = REGION.max.x + 1, REGION.max.y + 1
image = Image.new("RGB", (imgx, imgy), BACKGR) # create color image
draw = ImageDraw.Draw(image)
def draw_rect(rect, fill=None, outline=WHITE):
draw.rectangle([(rect.min.x, rect.min.y), (rect.max.x, rect.max.y)],
fill=fill, outline=outline)
# first draw outlines of all the non-overlapping rectanges generated
for rect in rects:
draw_rect(rect, outline=LIGHT_GRAY)
# then draw the random sample of them selected
for rect in sample:
draw_rect(rect, fill=RECT_COLOR, outline=WHITE)
# and lastly convert those into squares and re-draw them in another color
for rect in sample:
draw_rect(square_subregion(rect), fill=SQUARE_COLOR, outline=WHITE)
filename = 'square_quadsections.png'
image.save(filename, "PNG")
print repr(filename), 'output image saved'
+1, grande approche! La visualisation de PIL est une belle touche aussi :)
+1 a l'air bien! Je l'aime bien! Je vais certainement utiliser cela dans l'un de mes projets. Toute chance que vous puissiez trouver une variante qui produit carrés parfaites i> de tailles aléatoires à des endroits aléatoires?
@John: Eh bien, oui, je suis sûr que je pourrais, bien que cela soit techniquement une nouvelle question.
@Martineau: C'est ce que je me demandais, pensez-vous que je devrais poser une nouvelle question ou deviendrait-il fermé comme une dupe?
@John: HMMM, n'a jamais pensé à la possibilité de dupe. Dites-vous quoi, si vous acceptez ma réponse actuelle tel qu'il est, je vais le mettre à jour pour répondre à votre question suivante.
Il y a une approximation très simple à votre problème qui a bien fonctionné pour moi: P>
J'ai utilisé ceci pour générer au hasard une carte 2D (Zelda comme). Les images d'objets sont plus petites que <100 * 100>, donc j'ai utilisé la grille de taille <500 * 500> et autorisé pour 1 à 6 objets dans chaque grille. P>
Dans mon cas, j'ai eu un problème similaire, sauf que j'avais quelques rectangles précontrants à l'intérieur du rectangle global. Donc, de nouveaux rectangles ont dû être placés autour de ceux existants. P>
J'ai utilisé une approche gourmande: p>
Cela nécessite une conversion de votre espace de coordonnées d'origine vers / depuis l'espace de la grille, mais directement à faire. P>
(Notez que courir Kadene directement sur l'original, le rectangle global est à long terme. Aller via une approximation de la grille est assez rapide pour mon application) P>
Les rectangles sont-elles tailles aléatoires? Tailles prédéfinies? Toute la même taille?
Quelle est la résolution de la toile et de la taille des objets?