Detectar una "descolision" entre actores iguales?

Hola @jordinur, en este caso me parece que lo mejor sería utilizar el atributo figuras_en_contacto que tienen los objetos físicos.

Acá armé un ejemplo de cómo se podría usar esta forma de detección de colisiones:

y el código:

# coding: utf-8
import pilasengine

pilas = pilasengine.iniciar()

indicador_de_colision = pilas.actores.Texto("HAY COLISION!", y=100)
indicador_de_colision.transparencia = 100

class PelotaTransparente(pilasengine.actores.Pelota):
    
    def iniciar(self):
        pilasengine.actores.Pelota.iniciar(self)
        self.aprender('arrastrable')
        self.colisionando = False
    
    def actualizar(self):
        
        if self.figura_de_colision.figuras_en_contacto:
            self.transparencia = 0
            if not self.colisionando:
                self.colisionando = True
                self.entra_en_colision()
        else:
            self.transparencia = 50
            if self.colisionando:
                self.colisionando = False
                self.sale_de_la_colision()

    def entra_en_colision(self):
        indicador_de_colision.transparencia = 0
        
    def sale_de_la_colision(self):
        indicador_de_colision.transparencia = 100

pilas.actores.vincular(PelotaTransparente)
pilas.actores.PelotaTransparente()

pilas.ejecutar()

Avisame si te sirve!

1 Like

Hola Hugo! :smile:

Muchas gracias por responder, me parece muy adecuada tu recomendación de usar figuras_en_contacto en vez de colisiones, ya que eso me evita muchos problemas que se me planteaban.

Por ejemplo me evita la cuestión de si las figuras colisionan en horizontal, vertical, en L o en T ( lo cual me estaba volviendo loco).

Dicho esto, voy a estudiar bien tu código, porque ahora mismo me suena todo como “a marciano” ( ya que no habia usado antes estas cualidades de los actores y hay varias cosas que no entiendo de lu código) así que me pongo en serio a ello.

De todas formas, y aún pensando que debes creer que yo mismo lo voy a resolver, te agradeceria (si dispones de tiempo) un ejemplo de figuras en contacto entre varios actores iguales, ya que eso me evitaria muchas horas de experimentar prueba-error.

Muchas gracias de antemano. :wink:

EDITO:

Bueno no sé si es lo correcto, pero creo que ya lo encontré… Por favor, si no es así agradeceré una rectificación. :blush:

class PelotaTransparente(pilasengine.actores.Mono):
    
    def iniciar(self):
        pilasengine.actores.Mono.iniciar(self)
        self.aprender('arrastrable')
        self.colisionando = False
        self.es_mono = True
    
    def actualizar(self):
        
        if self.figura_de_colision.figuras_en_contacto:
            if len(self.figura_de_colision.figuras_en_contacto) > 2 and self.es_mono:
            
				self.transparencia = 0
				print(len(self.figura_de_colision.figuras_en_contacto))
				if not self.colisionando:
					self.colisionando = True
					self.entra_en_colision()
        else:
            self.transparencia = 50
            if self.colisionando:
                self.colisionando = False
                self.sale_de_la_colision()

    def entra_en_colision(self):
        indicador_de_colision.transparencia = 0
        
    def sale_de_la_colision(self):
        indicador_de_colision.transparencia = 100

pilas.actores.vincular(PelotaTransparente)
pilas.actores.PelotaTransparente()*3

Buenas @jordinur, las figuras tienen un atributo que te permite llegar al actor enlazado a la figura. Tal vez podrías usar ese atributo en conjunto con las etiquetas para chequear que sean actores de la misma especie.

Acá documenté sobre ese atributo hace unos minutos:

http://manual.pilas-engine.com.ar/colisiones/#deteccion-constante-de-colisiones

Lo escribí recién, puede tener algún detalle para corregir. Avisame cualquier cosa.

Abrazo!

Muchas gracias Hugo!

Qué gran trabajo!

La verdad, este tema me está superando un poco…

El problema era que en una grilla de (por ejemplo) 5 x 5 actores TODOS estaban en contacto entre ellos de una manera u otra. Por tanto, era muy difícil discernir cuando estaban en contacto entre actores iguales o cuando con diferentes.

Pero gracias a esa nueva documentación (que te aseguro que buena parte del código ni lo entiendo) creo verlo un poco más factible. Voy a estudiarmela MUY bien!!!

Lo que aún no tengo muy claro es por qué ese código debe ir en la def actualizar del actor y no en la de la escena… a mí la lógica me indicaba lo segundo! :disappointed_relieved:

De nuevo muchas gracias, :smile:

Si, es válido ponerlo en el “actualizar” de la escena, de hecho creo que puede ser mejor colocarlo en el “actualizar” de la escena.

Yo simplemente lo coloqué en método “actualizar” del actor porque pensé en un ejemplo pequeño, sin definir una escena propia. Pero claro, como en tu caso hay una escena es mejor colocar el código ahí. Así la lógica del juego te queda en un solo lugar, y se ejecuta una sola vez por actualización.

1 Like

Buenas @hugoruscitti !

La verdad es que este juego me lleva por el camino de la desesperación. Realmente no consigo que las fichas se eliminen al estar en contacto…
El ejemplo que pusiste funciona estupendamente para saber con que actor está colisionando individualmente, pero cuando se trata de colisiones múltiples entre actores iguales no me acaba de funcionar.

Lo primero, que sólo con que un actor tenga la etiqueta “pelotatransparente”, ya entra a la condición IF, aunque esté colisionando con uno o varios que no la tengan.

Lo segundo, que len(self.figura_de_colision.figuras_en_contacto) devuelve un valor de actores en contacto -1, ya que detecta colisiones y no actores. Entre 3 actores sólo hay 2 colisiones. Con esto se consigue eliminar 2 actores, pero siempre queda uno por eliminar.

Habria alguna forma de implementar un método que comprobara colisiones múltiples, de 3 actores IGUALES en horizontal o en vertical en una grilla y que al detectarlos los eliminara???

No quiero robarte tu tiempo, si crees que la solución es sencilla te agradeceré una aclaración, pero si vas a tener que dedicar unas horas que no tienes prefiero que lo dejes estar, por que me temo que con este tema he dado con varios problemas que superan de largo mis conocimientos.

Muchas gracias, y un abrazo.

Hola @jordinur !!, ¿me compartirías una captura de pantalla del juego?, Tal vez se pueda implementar alguna estrategia diferente, como superponer figuras transparentes para detectar las colisiones en linea o algo como areas de colisión más grandes.

Otra opción es que solo se intenten chequear las colisiones con el actor que se está moviendo con el mouse…

Pero hagamos una cosa mejor, publicá un screenshot y vemos que otra estrategia se puede implementar.

Buenas, @hugoruscitti !

Le he estdo dando muchas vueltas al asunto… creo que voy a enfocarlo de otra forma, usando una matriz y etiquetas en los actores en vez de colisiones. Te agradeceria si le echas un vistazo a este pequeño código de ejemplo, muy sencillo pero funcional, y que me digas si lo ves factible, y si puedes darme algún consejo que me ayude.

Muchas gracias por adelantado. :smile:

# -*- encoding: utf-8 -*-

import pilasengine
pilas = pilasengine.iniciar()

grilla = [[1,2,3],
			[4,5,6],
			[7.8,9]]


grilla[0][0] = pilas.actores.Mono()
grilla[0][0].x = -200
grilla[0][0].esmono = True

grilla[0][1] = pilas.actores.Aceituna()
grilla[0][1].escala = 3
grilla[0][1].esmono = True

grilla[0][2] = pilas.actores.Actor()
grilla[0][2].x = 200
grilla[0][2].esmono = True

print(grilla)

def comprobar():
	print('comprobando')
	if grilla[0][0].esmono:
		print('comprobando1')
		if grilla[0][1].esmono:
			print('comprobando2')
			if grilla[0][2].esmono:
				print('comprobando3')
				print(grilla)
				grilla[0][0].eliminar()
				grilla[0][0] = 1
				grilla[0][1].eliminar()
				grilla[0][1] = 2
				grilla[0][2].eliminar()
				grilla[0][2] = 3
				print('eliminando')
				print(grilla)
				
pilas.tareas.agregar(3, comprobar)

pilas.ejecutar()

Y aún diré más: :wink:

Aún faltaria hacer una comprobación vertical, y añadir un método de asignación de actores aleatorio… pero ceo que encontré el buen camino. :smile:

Cualquier sugerencia o ayuda serán bien venidas!

# -*- encoding: utf-8 -*-

import pilasengine
pilas = pilasengine.iniciar(ancho=800)

grilla = [[1,2,3,4,5],
			[6,7,8,9,10],
			[11,12,13,14,15]]

####### FILA 1
grilla[0][0] = pilas.actores.Mono()
grilla[0][0].x = -300
grilla[0][0].y = 150
grilla[0][0].esmono = 0

grilla[0][1] = pilas.actores.Aceituna()
grilla[0][1].escala = 3
grilla[0][1].esmono = 0
grilla[0][1].x = -150
grilla[0][1].y = 150

grilla[0][2] = pilas.actores.Actor()
grilla[0][2].x = 0
grilla[0][2].esmono = 0
grilla[0][2].y = 150

grilla[0][3] = pilas.actores.Actor()
grilla[0][3].x = 150
grilla[0][3].esmono = 1 # este es diferente para comprobar
grilla[0][3].y = 150

grilla[0][4] = pilas.actores.Actor()
grilla[0][4].x = 300
grilla[0][4].esmono = 0
grilla[0][4].y = 150

#######FILA2
grilla[1][0] = pilas.actores.Mono()
grilla[1][0].x = -300
grilla[1][0].esmono = 1

grilla[1][1] = pilas.actores.Aceituna()
grilla[1][1].escala = 3
grilla[1][1].esmono = 1
grilla[1][1].x = -150

grilla[1][2] = pilas.actores.Actor()
grilla[1][2].x = 0
grilla[1][2].esmono = 1

grilla[1][3] = pilas.actores.Actor()
grilla[1][3].x = 150
grilla[1][3].esmono = 1

grilla[1][4] = pilas.actores.Actor()
grilla[1][4].x = 300
grilla[1][4].esmono = 1

########FILA3
grilla[2][0] = pilas.actores.Mono()
grilla[2][0].x = -300
grilla[2][0].esmono = 2
grilla[2][0].y = -150

grilla[2][1] = pilas.actores.Aceituna()
grilla[2][1].escala = 3
grilla[2][1].esmono = 1 # este es diferente para comprobar
grilla[2][1].x = -150
grilla[2][1].y = -150

grilla[2][2] = pilas.actores.Actor()
grilla[2][2].x = 0
grilla[2][2].esmono = 2
grilla[2][2].y = -150


grilla[2][3] = pilas.actores.Actor()
grilla[2][3].x = 150
grilla[2][3].esmono = 2
grilla[2][3].y = -150

grilla[2][4] = pilas.actores.Actor()
grilla[2][4].x = 300
grilla[2][4].esmono = 2
grilla[2][4].y = -150


print(grilla)

def comprobar_horizontal():
	print('comprobando')

####### COMPROBACION ACTORES	
	for h in range(0,3):
		lista = []
		control = 0
		for k in range(0,3):
			for i in (grilla[h]):
				
				if (i.esmono) == k:
					print(i)
					lista.append(i)
					control += 1
					print(len(lista))
						
				else:
					if control <3:
						lista = []
						control = 0
					else:
						break
					
					print(len(lista))
						
						
		if len(lista) >=3 and control >=3:
			for j in lista:
				j.eliminar()
			lista = []	
			print(len(lista))
pilas.tareas.agregar(3, comprobar_horizontal)

pilas.ejecutar()

Hola @jordinur, me parece excelente.

Lo que se me ocurre para simplificarlo es usar alguna conversión de la matriz para chequear colisiones, por ejemplo podrías crear una matriz que solo contenga el tipo de actor por cada celda, así:

» matriz_nueva = [[x.esmono for x in fila] for fila in grilla]
» matriz_nueva 
[
 [0, 0, 0, 1, 0], 
 [1, 1, 1, 1, 1], 
 [2, 1, 2, 2, 2]
]

Es decir, una matriz, donde cada fila estará representada con el valor del atributo “esmono” de cada actor.

Lo interesante de esto es que podrías hacer chequeos en la linea completa, por ejemplo:

# ¿ Es una linea completa de unos ?
» matriz_nueva[1] == [1] * 5
True

# ¿ Es una linea completa de ceros ?
» matriz_nueva[1] == [0] * 5
False

# O directamente
» matriz_nueva[1] == [0, 0, 0, 0, 0]
False

Lo bueno de la matriz así armada con actores como la tenes es que también se puede filtrar, por ejemplo si querés los actores de la primer linea que tienen valor 1 en “esemno” podrías escribir:

» [actor for actor in grilla[0] if actor.esmono is 1]
[<Actor en (150, 150)>]

# o los que tienen valor 0
» [actor for actor in grilla[0] if actor.esmono is 0]
[<Mono en (-300, 150)>, <Aceituna en (-150, 150)>, <Actor en (0, 150)>, <Actor en (300, 150)>]

Buenas, @hugoruscitti !

Me parecen muy acertadas esas sugerencias ! Voy a probarlas y te digo como funciona.

Lo de darle un valor numérico a “esmono” ya lo hice, y funciona muy bien para detectar cuantos elementos hay en una fila con ese valor.

Me gusta eso que comentas de darle el valor esmono a cada celda de la matriz, ya que es uno de los errores que me saltan de vez en cuando y no sabia como resolverlo :smile:

El hecho es que ya he conseguido crear una matriz de 5 x 3 y un método para detectar si hay tres o más actores iguales en una fila y eliminarlos correctamente. Hasta ahí todo perfecto. El problema lo estoy teniendo al crear de nuevo los actores eliminados. Lo ideal seria que al eliminar los actores en una linea los que están por encima “bajaran” a ocupar su lugar, pero para empezar, y como primera prueba me conformaria con que los actores eliminados se volvieran a crear en las mismas posiciones. He logrado una buena parte, pero con varios errores que de momento no sé resolver.

Uno de los problemas es que no puedo crear un actor sin más, tengo que crearlo en una posición concreta de la grilla, y con unas coordenadas x.y… por ejemplo

grilla[1][4] = pilas.actores.ficha_mono(0,150)

Quizás me ayudaria poder darle a cada elemento de la matriz una posición x y fija para no tener que estarla definiendo cada vez?

Pero lo que más me está costanfo es poder darle a cada actor nuevo su posición en la grilla, ya que no sé como “sacar” la informacion de la posicion grilla[] []. De momento he probado con mi_lista.index(mi_elemento) y grilla.index(mi_lista) con resultados no muy convincentes. Es esa sensación de que casi lo tienes pero se te escapa entre los dedos :smile:

En el mejor de los casos he conseguido crear los actores en su lugar, pero se me han creado como 45 actores en vez de los 15 máximo que tiene mi matriz, supongo que por el abuso de “for in” reiterado en la creación del actor.

Esto es más que un reto personal… Creo que si se pudieran crear juegos tipo “Candy Crush” en Pilas atraeria a muchos posibles usuarios (al menos es mi imperesión).

De nuevo muchas gracias, ya iré informando si consigo nuevos progresos.

Un abrazo.

Buenas Hugo,

disculpa por ser tan pesado, pero gracias a tus consejos creo que he podido avanzar bastante, y casi diria que me he emocionado. :blush:

Al final me ha parecido más fácil simplemente cambiarle el atributo “esmono” a la ficha, más que eliminar y crear actores nuevos. Con esto se consigue que la ficha siga en su posición, pero que tenga otra imagen. Con esto tambien se evita tener que ir creando actores nuevos en la posición grilla[][] del actor eliminado, lo que lo simplifica todo y mucho.

Si dispones de tiempo, te agradeceria mucho si pudieras revisar este poco de código que tengo hasta ahora y me dijeras si lo ves factible… :slight_smile:

De mientras voy a tratar de implementar el método que creé para detectar si habia 3 o más figuras iguales juntas en una fila, para ver si todo encaja como seria de esperar.

Un abrazo.

# -*- encoding: utf-8 -*-
import pilasengine

pilas = pilasengine.iniciar(ancho=800)

class ficha(pilasengine.actores.Actor):
	def iniciar(self,x,y):
		x = self.x
		y = self.y
		self.transparencia = 100
		self.transparencia = [0],5
		self.aprender('puedeexplotar')
		self.esmono = pilas.azar(0,2)

	def actualizar(self):	
		if self.esmono == 0:
			self.imagen = 'data/mono.png'
			self.escala = 0.7
		elif self.esmono == 1:
			self.imagen = 'data/aceituna.png'
			self.escala = 2
		elif self.esmono == 2:
			self.imagen ='data/alien.png'
			self.escala = 1
pilas.actores.vincular(ficha)


grilla = [[pilas.actores.ficha(-300,150),pilas.actores.ficha(-150,150),pilas.actores.ficha(0,150),pilas.actores.ficha(150,150),pilas.actores.ficha(300,150)],
			[pilas.actores.ficha(-300,0),pilas.actores.ficha(-150,0),pilas.actores.ficha(0,0),pilas.actores.ficha(150,0),pilas.actores.ficha(300,0)],
			[pilas.actores.ficha(-300,-150),pilas.actores.ficha(-150,-150),pilas.actores.ficha(0,-150),pilas.actores.ficha(150,-150),pilas.actores.ficha(300,-150)]]


matriz_nueva = [[x.esmono for x in fila] for fila in grilla]
print ('matriz inicial:')
print(matriz_nueva)	

def cambiar_ficha(fichas_a_eliminar):
	random_cambiar = pilas.azar(0,2)
	fichas_a_eliminar.transparencia = [100]
	
	def cambiar_imagen():
		fichas_a_eliminar.esmono = random_cambiar
		fichas_a_eliminar.transparencia = [0],2
		
		global matriz_nueva # GLOBAL !!!!!
		
		matriz_nueva = [[x.esmono for x in fila] for fila in grilla]
		
		print('Cambiando Matriz:')
		print(matriz_nueva)

	pilas.tareas.agregar(3, cambiar_imagen)
	
def eliminar_y_crear():	
	# Con este método se podria elegir qué fichas deben ser cambiadas.
	# Se podria usar una etiqueta "eliminable = True" en las fichas
	# por ejemplo:
	# for ficha_eliminable in lista_fichas_eliminables:
	#		cambiar_ficha(ficha_eliminable)
	# O aun mas facil:
	# if ficha.eliminable:
	#	cambiar_ficha(ficha)
	
	for ficha_eliminable in grilla[0]: #cambiamos toda la fila superior
		cambiar_ficha(ficha_eliminable)

def comparar_matrices():
	print('')
	print('COMPARANDO MATRICES')
	print('')
	print ('Matriz cambiada:')
	print('')
	print (matriz_nueva)	

pilas.tareas.agregar(5, eliminar_y_crear) 
pilas.tareas.agregar(10, comparar_matrices)

pilas.ejecutar()
1 Like

Que interesante este post @jordinur.
Ya desarrollaste lo que querías con esto?
o esta vigente las propuestas, me sentare a comprender este amasijo de cosas interesantes que uds colocaron allí.
De verdad estoy muy contento que @hugoruscitti atienda a su comunidad como lo hace. Estoy recopilando la máxima información para ensenar programación a mis hijos, en especial al mayor que quiere ser desarrollador de videojuegos, y eso me encanta porque siempre quise pero lo fui postergando, y bueno ahora es que se da el momento.
Por eso es que me verán por allí leyendo y estudiando cuanto material este en pilas, y me objetivo en estos momentos es devolver el bien recibido con contribución de material, juegos y en su momento alguna explicación.

Y la elección de pilas es por muchas razones, en la primera es que es desarrollado por uno de la zona, dos es en español, tres que es python y ese lenguaje estaba en mi lista de propósitos para este año jejeje. Por su puesto que estan los otros motores que tienen diversos grados de complejidad y comodidad y popularidad, pero me decidí por pilasengine

Buenas, @Alejandro_Villalobos !

La verdad es que ese proyecto aún está a medias… de momento he conseguido crear una grilla de 5 x 3, y rellenarla aleatoriamente con 3 figuras diferentes. Tambien he implementado un método de identificación de “match 3” en horizontal y otro en vertical, y que las fichas se eliminen automáticamente si hay 3 iguales en contacto.

Ahora faltaria implementar el método de “mover una ficha” para seguir el juego, y eso me está complicando todo un poco, ya que la ficha deberia estar limitada a moverse sólo a una celda de la grilla adyacente. En eso estoy trabajando y espero resolverlo en breve.

Lo malo es que como ya comenté el código lo tengo en el disco duro de la PC averiada, y de momento no tengo manera de rescatarlo. Espero que en breve tenga ya mi nueva PC y que pueda recuperar todo ese código :scream: porque le he dedicado muchas horas y no me gustaria que se perdiera por nada del mundo !

En cuanto lo haya recuperado lo expondré aquí para ver si entre todos podemos “afinarlo” y mejorarlo y hacerlo más sencillo y funcional.

Un abrazo.

1 Like

Aqui tienes el código!!! :wink:

1 Like

Hola @jordinur, quisiera saber si sabes como hacer que la descolision solo funcione cuando es con un actor en especifico, veraz, logre entender el metodo y me sirve pero el problema es que solo quiero que la descolision de detecte cuando es con un actor en especifico y nose como hacerlo :confused:

Buenas, @Pan!

Uff ese código tiene ya su tiempo, es bastante complicado y ya casi ni me acuerdo :joy:

Creo recordar que se controlaban las colisiones con un atributo booleano True/False

ficha.es_mono = True
ficha.es_aceituna = False

ficha2.es_mono = False
ficha2.es_aceituna = True

def al_colisonar():
    if ficha.es_mono:
        haz esto
    elif ficha.es_aceituna:
        haz esto otro
    else:
        no hagas nada

Un saludo! :wink:

1 Like

Ouh, gracias, no se me habia ocurrido esa forma :stuck_out_tongue:

Tube que agregar una colision para que me funcionara, aqui tienes el codigo por si alguna vez lo necesitas ^^

# coding: utf-8
import pilasengine

pilas = pilasengine.iniciar()

class Mono2(pilasengine.actores.Mono):
    def iniciar(self):
        self.aprender('arrastrable')
        self.colisionando = False
        self.es_aceituna = False
        self.es_banana = False
        pilas.colisiones.agregar("Mono2","Aceituna", self.colision)
        pilas.colisiones.agregar("Mono2","Banana", self.colision2)
    def actualizar(self):
        if self.figura_de_colision.figuras_en_contacto:
            if not self.colisionando:
                self.colisionando = True
                pilas.tareas.una_vez(0.1, self.colisiona)
        else:
            if self.colisionando:
                self.colisionando = False
                pilas.tareas.una_vez(0.1, self.descolisiona)
                
    def colisiona(self):
        if self.es_aceituna==True:
            pilas.avisar("colision con aceituna")
        elif self.es_banana==True:
            pilas.avisar("colision con banana")
        
    def descolisiona(self):
        if self.es_aceituna==True:
            pilas.avisar("descolision  con aceituna")
            self.es_aceituna=False
        elif self.es_banana==True:
            pilas.avisar("descolision  con banana")
            self.es_banana=False
    def colision(self):
        self.es_aceituna=True
    def colision2(self):
        self.es_banana=True
        
pilas.actores.vincular(Mono2)
pilas.actores.Mono2()

aceituna = pilas.actores.Banana()
aceituna = pilas.actores.Aceituna()
aceituna.aprender('arrastrable')

pilas.ejecutar()
2 Likes

4 publicaciones han sido separadas a un nuevo tema: Cómo implementar colisiones